-- Migration 020: restore_list() + hard_delete_list() RPCs — Fase 10.4.
-- (Migration number 019 intentionally reserved; see plan/fase-10-spec-completion.md.)
--
-- Both functions are SECURITY DEFINER and guard explicitly on caller
-- membership (admin or member; guests cannot mutate). They give the
-- trash drawer a single round-trip that does what it says, instead of
-- chained PostgREST UPDATEs (which evaluate SELECT RLS on the returned
-- row — see CLAUDE.md "Backend / RLS / Kong" gotcha).

-- ── restore_list ─────────────────────────────────────────────────────────────
-- Clear deleted_at on a soft-deleted list. Rejects if the list is not
-- currently soft-deleted (defensive — restore on an active list is a no-op
-- but tests can rely on the throw to detect logic errors).

CREATE OR REPLACE FUNCTION public.restore_list(p_list_id uuid)
RETURNS void
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public, auth
AS $$
DECLARE
    v_user uuid := auth.uid();
    v_collective uuid;
    v_role public.member_role;
    v_deleted timestamptz;
BEGIN
    IF v_user IS NULL THEN
        RAISE EXCEPTION 'not authenticated' USING ERRCODE = '28000';
    END IF;

    SELECT collective_id, deleted_at INTO v_collective, v_deleted
    FROM public.shopping_lists
    WHERE id = p_list_id;

    IF v_collective IS NULL THEN
        RAISE EXCEPTION 'list not found' USING ERRCODE = 'P0404';
    END IF;

    SELECT role INTO v_role
    FROM public.collective_members
    WHERE collective_id = v_collective AND user_id = v_user;

    IF v_role IS NULL OR v_role = 'guest' THEN
        RAISE EXCEPTION 'not allowed' USING ERRCODE = '42501';
    END IF;

    IF v_deleted IS NULL THEN
        RAISE EXCEPTION 'list is not in trash' USING ERRCODE = 'P0001';
    END IF;

    UPDATE public.shopping_lists SET deleted_at = NULL WHERE id = p_list_id;
END;
$$;

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

-- ── hard_delete_list ─────────────────────────────────────────────────────────
-- Permanently delete a list that is already in the trash. Rejects if the
-- list is still active (i.e. not soft-deleted yet) — the user must trash
-- it first. shopping_items cascade on the FK.

CREATE OR REPLACE FUNCTION public.hard_delete_list(p_list_id uuid)
RETURNS void
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public, auth
AS $$
DECLARE
    v_user uuid := auth.uid();
    v_collective uuid;
    v_role public.member_role;
    v_deleted timestamptz;
BEGIN
    IF v_user IS NULL THEN
        RAISE EXCEPTION 'not authenticated' USING ERRCODE = '28000';
    END IF;

    SELECT collective_id, deleted_at INTO v_collective, v_deleted
    FROM public.shopping_lists
    WHERE id = p_list_id;

    IF v_collective IS NULL THEN
        RAISE EXCEPTION 'list not found' USING ERRCODE = 'P0404';
    END IF;

    SELECT role INTO v_role
    FROM public.collective_members
    WHERE collective_id = v_collective AND user_id = v_user;

    IF v_role IS NULL OR v_role = 'guest' THEN
        RAISE EXCEPTION 'not allowed' USING ERRCODE = '42501';
    END IF;

    IF v_deleted IS NULL THEN
        RAISE EXCEPTION 'list is not in trash' USING ERRCODE = 'P0001';
    END IF;

    DELETE FROM public.shopping_lists WHERE id = p_list_id;
END;
$$;

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