-- ============================================================================
-- Stripe Integration - Custom Extensions
-- ============================================================================
-- This file adds custom functionality on top of @supabase/stripe-sync-engine
-- The library creates and manages all stripe.* tables - we don't modify them!
-- We only: create views, add profile integration, and helper functions
-- ============================================================================
-- IMPORTANT: Run the stripe-sync-engine migrations FIRST before running this!
-- See: docs/STRIPE_WITH_SYNC_ENGINE.md
-- ============================================================================

-- ============================================================================
-- Functions to Access Stripe Data (Security Definer)
-- ============================================================================
-- Since we don't modify the stripe schema, we use security definer functions
-- to access the data and filter by user_id from metadata
-- ============================================================================

-- Function to get user's customer record
create or replace function public.get_user_stripe_customer()
returns table (
  id text,
  email text,
  user_id uuid,
  created integer,
  metadata jsonb
)
language plpgsql
security definer
as $$
begin
  return query
  select 
    c.id,
    c.email,
    (c.metadata->>'user_id')::uuid as user_id,
    c.created,
    c.metadata
  from stripe.customers c
  where (c.metadata->>'user_id')::uuid = auth.uid();
end;
$$;

-- Function to get user's subscriptions
create or replace function public.get_user_stripe_subscriptions()
returns table (
  id text,
  customer text,
  user_id uuid,
  status text,
  items jsonb,
  cancel_at_period_end boolean,
  current_period_start integer,
  current_period_end integer,
  created integer,
  canceled_at integer,
  trial_start jsonb,
  trial_end jsonb,
  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.items,
    s.cancel_at_period_end,
    s.current_period_start,
    s.current_period_end,
    s.created,
    s.canceled_at,
    s.trial_start,
    s.trial_end,
    s.metadata
  from stripe.subscriptions s
  inner join stripe.customers c on c.id = s.customer
  where (c.metadata->>'user_id')::uuid = auth.uid();
end;
$$;

-- Function to get all stripe products (public access)
create or replace function public.get_stripe_products()
returns table (
  id text,
  name text,
  description text,
  active boolean,
  created integer,
  metadata jsonb
)
language plpgsql
security definer
as $$
begin
  return query
  select 
    p.id,
    p.name,
    p.description,
    p.active,
    p.created,
    p.metadata
  from stripe.products p
  where p.active = true;
end;
$$;

-- Function to get all stripe prices (public access)
create or replace function public.get_stripe_prices()
returns table (
  id text,
  product text,
  active boolean,
  currency text,
  unit_amount integer,
  recurring jsonb,
  created integer,
  metadata jsonb
)
language plpgsql
security definer
as $$
begin
  return query
  select 
    pr.id,
    pr.product,
    pr.active,
    pr.currency,
    pr.unit_amount,
    pr.recurring,
    pr.created,
    pr.metadata
  from stripe.prices pr
  where pr.active = true;
end;
$$;

-- ============================================================================
-- Add subscription status to profiles
-- ============================================================================

-- Add is_paying column to profiles table
alter table public.profiles 
add column if not exists is_paying boolean default false;

-- Add subscription_tier column to profiles table  
alter table public.profiles 
add column if not exists subscription_tier text default 'free';

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

-- Function to check if a user is a paying subscriber
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
    where (c.metadata->>'user_id')::uuid = user_uuid
      and s.status::text in ('active', 'trialing')
      and to_timestamp(s.current_period_end) > now()
  ) into has_active_subscription;
  
  return has_active_subscription;
end;
$$;

-- Function to get user's subscription status
create or replace function public.get_user_subscription_status(user_uuid uuid)
returns table (
  subscription_id text,
  status text,
  current_period_end integer,
  cancel_at_period_end boolean,
  items jsonb,
  product_name text
)
language plpgsql
security definer
as $$
declare
  first_item jsonb;
  price_id text;
begin
  return query
  select 
    s.id,
    s.status::text,
    s.current_period_end,
    s.cancel_at_period_end,
    s.items,
    p.name as product_name
  from stripe.subscriptions s
  inner join stripe.customers c on c.id = s.customer
  left join lateral (
    select (s.items->'data'->0->>'price')::text as extracted_price_id
  ) price_extract on true
  left join stripe.prices pr on pr.id = price_extract.extracted_price_id
  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')
  order by s.current_period_end desc
  limit 1;
end;
$$;

-- Function to get user's Stripe customer ID
create or replace function public.get_user_stripe_customer_id(user_uuid uuid)
returns text
language plpgsql
security definer
as $$
declare
  customer_id text;
begin
  select id into customer_id
  from stripe.customers
  where (metadata->>'user_id')::uuid = user_uuid
  limit 1;
  
  return customer_id;
end;
$$;

-- Function to update profile subscription status
-- Drop the function to update profile subscription status
drop function if exists public.update_profile_subscription_status();
create function public.update_profile_subscription_status()
returns trigger as $$
declare
  v_user_id uuid;
  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;
  
  -- Update the user's profile when subscription changes
  update public.profiles
  set 
    is_paying = (
      select exists(
        select 1
        from stripe.subscriptions s
        inner join stripe.customers c on c.id = s.customer
        where (c.metadata->>'user_id')::uuid = v_user_id
          and s.status::text in ('active', 'trialing')
          and to_timestamp(s.current_period_end) > now()
      )
    ),
    subscription_tier = (
      case
        when new.status::text in ('active', 'trialing') then 'standard'
        else 'free'
      end
    )
  where id = v_user_id;
  
  return new;
end;
$$ language plpgsql security definer;

-- Trigger to update profile when subscription changes
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();
  
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();

-- ============================================================================
-- Views for convenience
-- ============================================================================

-- View for active subscriptions with user info
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(s.current_period_start) as current_period_start,
  to_timestamp(s.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
from stripe.subscriptions s
inner join stripe.customers c on c.id = s.customer
inner join public.profiles p on p.id = (c.metadata->>'user_id')::uuid
left join lateral (
  select (s.items->'data'->0->>'price')::text as extracted_price_id
) price_extract on true
left join stripe.prices pc on pc.id = price_extract.extracted_price_id
left join stripe.products pr on pr.id = pc.product
where s.status::text in ('active', 'trialing')
  and to_timestamp(s.current_period_end) > now()
  and (c.metadata->>'user_id') is not null;

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

comment on view public.active_subscriptions is 'Active subscriptions joined with user profile data';

comment on function public.get_user_stripe_customer is 'Returns current user''s customer record from Stripe';
comment on function public.get_user_stripe_subscriptions is 'Returns current user''s subscriptions from Stripe';
comment on function public.get_stripe_products is 'Returns all active Stripe products (public access)';
comment on function public.get_stripe_prices is 'Returns all active Stripe prices (public access)';
comment on function public.is_paying_user is 'Returns true if user has an active or trialing subscription';
comment on function public.get_user_subscription_status is 'Returns current subscription details for a user';
comment on function public.get_user_stripe_customer_id is 'Returns the Stripe customer ID for a user';
comment on function public.update_profile_subscription_status is 'Trigger function to update profile fields when subscription changes';

