-- ============================================================================
-- Fix Stripe Subscription Period Dates
-- ============================================================================
-- This migration fixes the subscription logic to use subscription_items 
-- for current_period_end (the actual billing cycle end date) instead of
-- subscriptions.current_period_end (which is NULL for ongoing subscriptions)
-- 
-- Changes:
-- 1. Remove is_paying column from profiles
-- 2. Add plan enum column to profiles (trial, standard, none)
-- 3. Update all functions to use subscription_items.current_period_end
-- ============================================================================

-- ============================================================================
-- Create plan enum type
-- ============================================================================

do $$ 
begin
  if not exists (select 1 from pg_type where typname = 'subscription_plan') then
    create type subscription_plan as enum ('none', 'trial', 'standard');
  end if;
end $$;

-- ============================================================================
-- Update profiles table
-- ============================================================================

-- Remove is_paying column
alter table public.profiles 
drop column if exists is_paying;

-- Remove subscription_tier column (replaced with plan)
alter table public.profiles 
drop column if exists subscription_tier;

-- Add plan column
alter table public.profiles 
add column if not exists plan subscription_plan default 'none';

-- ============================================================================
-- Updated Helper Functions
-- ============================================================================

-- Function to check if a user is a paying subscriber (using subscription_items)
create or replace function public.is_paying_user(user_uuid uuid)
returns boolean
language plpgsql
security definer
as $$
declare
  has_active_subscription boolean;
begin
  select exists(
    select 1
    from stripe.subscriptions s
    inner join stripe.customers c on c.id = s.customer
    inner join stripe.subscription_items si on si.subscription = s.id
    where (c.metadata->>'user_id')::uuid = user_uuid
      and s.status::text in ('active', 'trialing')
      and si.current_period_end is not null
      and to_timestamp(si.current_period_end) > now()
  ) into has_active_subscription;
  
  return has_active_subscription;
end;
$$;

-- Function to get user's subscription status (using subscription_items)
create or replace function public.get_user_subscription_status(user_uuid uuid)
returns table (
  subscription_id text,
  status text,
  current_period_start integer,
  current_period_end integer,
  cancel_at_period_end boolean,
  price_id text,
  product_name text,
  plan subscription_plan
)
language plpgsql
security definer
as $$
begin
  return query
  select 
    s.id,
    s.status::text,
    si.current_period_start,
    si.current_period_end,
    s.cancel_at_period_end,
    si.price as price_id,
    p.name as product_name,
    case
      when s.status::text = 'trialing' then 'trial'::subscription_plan
      when s.status::text in ('active', 'past_due') then 'standard'::subscription_plan
      else 'none'::subscription_plan
    end as plan
  from stripe.subscriptions s
  inner join stripe.customers c on c.id = s.customer
  inner join stripe.subscription_items si on si.subscription = s.id
  left join stripe.prices pr on pr.id = si.price
  left join stripe.products p on p.id = pr.product
  where (c.metadata->>'user_id')::uuid = user_uuid
    and s.status::text in ('active', 'trialing', 'past_due')
    and si.current_period_end is not null
  order by si.current_period_end desc
  limit 1;
end;
$$;

-- ============================================================================
-- Updated Trigger Function
-- ============================================================================

-- Function to update profile subscription plan
create or replace function public.update_profile_subscription_status()
returns trigger as $$
declare
  v_user_id uuid;
  v_plan subscription_plan;
  v_customer_id text;
begin
  -- Get customer ID based on which table triggered this
  if TG_TABLE_NAME = 'subscriptions' then
    v_customer_id := new.customer;
  elsif TG_TABLE_NAME = 'subscription_items' then
    -- Get customer ID from the subscription
    select customer into v_customer_id
    from stripe.subscriptions
    where id = new.subscription;
  else
    -- Unknown table, skip
    return new;
  end if;
  
  -- Skip if no customer_id found
  if v_customer_id is null then
    return new;
  end if;
  
  -- Extract user_id from customer metadata
  select (metadata->>'user_id')::uuid into v_user_id
  from stripe.customers
  where id = v_customer_id;
  
  -- Skip if no user_id found
  if v_user_id is null then
    return new;
  end if;
  
  -- Determine the user's current plan
  select 
    case
      when exists(
        select 1
        from stripe.subscriptions s
        inner join stripe.customers c on c.id = s.customer
        inner join stripe.subscription_items si on si.subscription = s.id
        where (c.metadata->>'user_id')::uuid = v_user_id
          and s.status::text = 'trialing'
          and si.current_period_end is not null
          and to_timestamp(si.current_period_end) > now()
      ) then 'trial'::subscription_plan
      when exists(
        select 1
        from stripe.subscriptions s
        inner join stripe.customers c on c.id = s.customer
        inner join stripe.subscription_items si on si.subscription = s.id
        where (c.metadata->>'user_id')::uuid = v_user_id
          and s.status::text in ('active', 'past_due')
          and si.current_period_end is not null
          and to_timestamp(si.current_period_end) > now()
      ) then 'standard'::subscription_plan
      else 'none'::subscription_plan
    end into v_plan;
  
  -- Update the user's profile
  update public.profiles
  set plan = v_plan
  where id = v_user_id;
  
  return new;
end;
$$ language plpgsql security definer;

-- Recreate trigger (it already exists from previous migration)
drop trigger if exists update_profile_on_subscription_change on stripe.subscriptions;
create trigger update_profile_on_subscription_change
  after insert or update on stripe.subscriptions
  for each row
  execute function public.update_profile_subscription_status();

-- Also create trigger on subscription_items since that's where period dates are
drop trigger if exists update_profile_on_subscription_item_change on stripe.subscription_items;
create trigger update_profile_on_subscription_item_change
  after insert or update on stripe.subscription_items
  for each row
  execute function public.update_profile_subscription_status();

-- ============================================================================
-- Updated Views
-- ============================================================================

-- View for active subscriptions with user info (using subscription_items)
create or replace view public.active_subscriptions as
select 
  s.id as subscription_id,
  (c.metadata->>'user_id')::uuid as user_id,
  p.email as user_email,
  p.first_name,
  p.last_name,
  s.status::text,
  to_timestamp(si.current_period_start) as current_period_start,
  to_timestamp(si.current_period_end) as current_period_end,
  s.cancel_at_period_end,
  pr.name as product_name,
  pc.currency,
  pc.unit_amount,
  pc.recurring->>'interval' as interval,
  p.plan
from stripe.subscriptions s
inner join stripe.customers c on c.id = s.customer
inner join stripe.subscription_items si on si.subscription = s.id
inner join public.profiles p on p.id = (c.metadata->>'user_id')::uuid
left join stripe.prices pc on pc.id = si.price
left join stripe.products pr on pr.id = pc.product
where s.status::text in ('active', 'trialing')
  and si.current_period_end is not null
  and to_timestamp(si.current_period_end) > now()
  and (c.metadata->>'user_id') is not null;

-- ============================================================================
-- Update RPC function to return subscription with correct period dates
-- ============================================================================

-- Function to get user's subscriptions (updated to use subscription_items)
create or replace function public.get_user_stripe_subscriptions()
returns table (
  id text,
  customer text,
  user_id uuid,
  status text,
  cancel_at_period_end boolean,
  current_period_start integer,
  current_period_end integer,
  created integer,
  canceled_at integer,
  trial_start jsonb,
  trial_end jsonb,
  price_id text,
  quantity integer,
  metadata jsonb
)
language plpgsql
security definer
as $$
begin
  return query
  select 
    s.id,
    s.customer,
    (c.metadata->>'user_id')::uuid as user_id,
    s.status::text,
    s.cancel_at_period_end,
    si.current_period_start,
    si.current_period_end,
    s.created,
    s.canceled_at,
    s.trial_start,
    s.trial_end,
    si.price as price_id,
    si.quantity,
    s.metadata
  from stripe.subscriptions s
  inner join stripe.customers c on c.id = s.customer
  left join stripe.subscription_items si on si.subscription = s.id
  where (c.metadata->>'user_id')::uuid = auth.uid()
  order by s.created desc;
end;
$$;

-- ============================================================================
-- Comments for documentation
-- ============================================================================

comment on column public.profiles.plan is 'User subscription plan: none (free), trial, or standard';
comment on function public.get_user_subscription_status is 'Returns current subscription details using subscription_items for accurate period dates';


