-- Private-by-default follow model + mutuals enforcement

-- 1) Profiles: add privacy/official flags
alter table if exists profiles
  add column if not exists is_private boolean not null default true,
  add column if not exists is_official boolean not null default false;

-- 2) Follows: add status and constraint
alter table if exists follows
  add column if not exists status text not null default 'accepted';

do $$
begin
  if not exists (
    select 1
    from pg_constraint
    where conname = 'follows_status_check'
  ) then
    alter table follows
      add constraint follows_status_check
      check (status in ('pending', 'accepted'));
  end if;
end $$;

-- 3) Request follow function (privacy-aware)
create or replace function request_follow(target_id uuid)
returns text
language plpgsql
security definer
as $$
declare
  existing_status text;
  target_private boolean;
  target_official boolean;
  new_status text;
begin
  if auth.uid() is null then
    raise exception 'Not authenticated';
  end if;

  select status into existing_status
  from follows
  where follower_id = auth.uid()
    and following_id = target_id;

  if existing_status is not null then
    return existing_status;
  end if;

  select is_private, is_official
    into target_private, target_official
  from profiles
  where id = target_id;

  if target_private is null then
    raise exception 'Target profile not found';
  end if;

  if target_official or target_private = false then
    new_status := 'accepted';
  else
    new_status := 'pending';
  end if;

  insert into follows (follower_id, following_id, status)
  values (auth.uid(), target_id, new_status);

  return new_status;
end;
$$;

-- 4) Mutual follow must be accepted on both sides
create or replace function is_mutual_follow(user_a uuid, user_b uuid)
returns boolean
language plpgsql
security definer
as $$
begin
  return exists (
    select 1
    from follows f1
    where f1.follower_id = user_a
      and f1.following_id = user_b
      and f1.status = 'accepted'
  ) and exists (
    select 1
    from follows f2
    where f2.follower_id = user_b
      and f2.following_id = user_a
      and f2.status = 'accepted'
  );
end;
$$;

-- 5) Follow request management helpers
create or replace function accept_follow_request(requester_id uuid)
returns void
language plpgsql
security definer
as $$
begin
  if auth.uid() is null then
    raise exception 'Not authenticated';
  end if;

  update follows
  set status = 'accepted'
  where follower_id = requester_id
    and following_id = auth.uid();
end;
$$;

create or replace function reject_follow_request(requester_id uuid)
returns void
language plpgsql
security definer
as $$
begin
  if auth.uid() is null then
    raise exception 'Not authenticated';
  end if;

  delete from follows
  where follower_id = requester_id
    and following_id = auth.uid();
end;
$$;

create or replace function get_follow_requests()
returns table (
  follower_id uuid,
  handle text,
  display_name text,
  avatar_url text,
  requested_at timestamptz
)
language sql
security definer
as $$
  select
    f.follower_id,
    p.handle,
    p.display_name,
    p.avatar_url,
    f.created_at as requested_at
  from follows f
  join profiles p on p.id = f.follower_id
  where f.following_id = auth.uid()
    and f.status = 'pending'
  order by f.created_at desc;
$$;

-- 6) Posts RLS: allow self, public, or accepted follow
alter table if exists posts enable row level security;

drop policy if exists posts_select_private_model on posts;
create policy posts_select_private_model on posts
  for select
  using (
    auth.uid() = author_id
    or exists (
      select 1
      from profiles p
      where p.id = author_id
        and p.is_private = false
    )
    or exists (
      select 1
      from follows f
      where f.follower_id = auth.uid()
        and f.following_id = author_id
        and f.status = 'accepted'
    )
  );
