-- Migration 017: leave_collective(uuid) RPC — Fase 10.1 (CU-H06).
--
-- A user abandons one of their collectives. The content stays.
--
-- If the user is the only admin and other members exist, the existing
-- `promote_oldest_member_on_admin_leave` trigger fires on DELETE FROM
-- public.users — but that trigger only runs on user-account delete, not
-- on collective_members delete. So we replicate the auto-promote logic
-- inline before removing the membership row.
--
-- If the user is the sole member of the collective, leaving is disallowed:
-- they must dissolve instead (CU-H08, migration 018). Errcode P0001 lets
-- the UI distinguish this case from generic errors and link to the
-- dissolve flow.

CREATE OR REPLACE FUNCTION public.leave_collective(p_collective_id uuid)
RETURNS void
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public, auth
AS $$
DECLARE
    v_user uuid := auth.uid();
    v_member_count int;
    v_is_admin boolean;
    v_other_admins int;
BEGIN
    IF v_user IS NULL THEN
        RAISE EXCEPTION 'not authenticated' USING ERRCODE = '28000';
    END IF;

    -- Guard: caller must actually be a member of the collective.
    IF NOT EXISTS (
        SELECT 1 FROM public.collective_members
        WHERE collective_id = p_collective_id AND user_id = v_user
    ) THEN
        RAISE EXCEPTION 'not a member' USING ERRCODE = '42501';
    END IF;

    -- How many members in the collective?
    SELECT count(*) INTO v_member_count
    FROM public.collective_members
    WHERE collective_id = p_collective_id;

    IF v_member_count = 1 THEN
        -- Sole member — must dissolve, not leave.
        RAISE EXCEPTION 'cannot leave as sole member; dissolve instead'
            USING ERRCODE = 'P0001';
    END IF;

    -- Check if the departing user is the only admin.
    SELECT role = 'admin' INTO v_is_admin
    FROM public.collective_members
    WHERE collective_id = p_collective_id AND user_id = v_user;

    IF v_is_admin THEN
        SELECT count(*) INTO v_other_admins
        FROM public.collective_members
        WHERE collective_id = p_collective_id
        AND   user_id <> v_user
        AND   role = 'admin';

        -- If sole admin, promote the oldest remaining (non-departing) member.
        IF v_other_admins = 0 THEN
            UPDATE public.collective_members
            SET    role = 'admin'
            WHERE  (collective_id, user_id) = (
                SELECT collective_id, user_id
                FROM   public.collective_members
                WHERE  collective_id = p_collective_id
                AND    user_id <> v_user
                ORDER  BY joined_at ASC
                LIMIT  1
            );
        END IF;
    END IF;

    DELETE FROM public.collective_members
    WHERE collective_id = p_collective_id AND user_id = v_user;
END;
$$;

REVOKE ALL ON FUNCTION public.leave_collective(uuid) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.leave_collective(uuid) TO authenticated;
