-- =====================================================
-- Soft Delete Consistency
--
-- Problem: deleteMember does a soft delete (status='resigned'),
-- but child table FKs use ON DELETE CASCADE. A hard DELETE
-- would silently destroy roles, honors, mandates, transfers
-- with no audit trail.
--
-- Fix: Change CASCADE to RESTRICT on data-preserving tables,
-- add BEFORE DELETE audit trigger, provide safe_delete_member().
-- =====================================================

-- Step 1: Change ON DELETE CASCADE → RESTRICT on tables where
-- child data has independent value and should be preserved.
-- We must drop and recreate the FK constraints.

-- member_roles: board positions have historical value
ALTER TABLE public.member_roles
  DROP CONSTRAINT IF EXISTS member_roles_member_id_fkey;
ALTER TABLE public.member_roles
  ADD CONSTRAINT member_roles_member_id_fkey
  FOREIGN KEY (member_id) REFERENCES public.members(id) ON DELETE RESTRICT;

-- member_honors: awards/medals are permanent records
ALTER TABLE public.member_honors
  DROP CONSTRAINT IF EXISTS member_honors_member_id_fkey;
ALTER TABLE public.member_honors
  ADD CONSTRAINT member_honors_member_id_fkey
  FOREIGN KEY (member_id) REFERENCES public.members(id) ON DELETE RESTRICT;

-- sepa_mandates: financial records must be preserved
ALTER TABLE public.sepa_mandates
  DROP CONSTRAINT IF EXISTS sepa_mandates_member_id_fkey;
ALTER TABLE public.sepa_mandates
  ADD CONSTRAINT sepa_mandates_member_id_fkey
  FOREIGN KEY (member_id) REFERENCES public.members(id) ON DELETE RESTRICT;

-- member_transfers: audit trail must survive
ALTER TABLE public.member_transfers
  DROP CONSTRAINT IF EXISTS member_transfers_member_id_fkey;
ALTER TABLE public.member_transfers
  ADD CONSTRAINT member_transfers_member_id_fkey
  FOREIGN KEY (member_id) REFERENCES public.members(id) ON DELETE RESTRICT;

-- Keep CASCADE on tables where data is tightly coupled:
-- member_department_assignments (junction table, no independent value)
-- member_cards (regeneratable)
-- member_portal_invitations (transient)

-- Step 2: Audit trigger before hard delete — snapshot the full record
CREATE OR REPLACE FUNCTION public.audit_member_before_hard_delete()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = ''
AS $$
BEGIN
  -- If an audit_log table exists, log the deletion
  INSERT INTO public.audit_log (
    account_id, user_id, table_name, record_id, action, old_data
  )
  SELECT
    OLD.account_id,
    COALESCE(
      nullif(current_setting('app.current_user_id', true), '')::uuid,
      auth.uid()
    ),
    'members',
    OLD.id::text,
    'delete',
    to_jsonb(OLD);

  RETURN OLD;
EXCEPTION
  WHEN undefined_table THEN
    -- audit_log table doesn't exist yet, allow delete to proceed
    RETURN OLD;
END;
$$;

CREATE TRIGGER trg_members_audit_before_delete
  BEFORE DELETE ON public.members
  FOR EACH ROW
  EXECUTE FUNCTION public.audit_member_before_hard_delete();

-- Step 3: Safe hard-delete function for super-admin use only
-- Archives all child records first, then performs the delete.
CREATE OR REPLACE FUNCTION public.safe_delete_member(
  p_member_id uuid,
  p_performed_by uuid DEFAULT NULL
)
RETURNS void
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = ''
AS $$
DECLARE
  v_member record;
BEGIN
  -- Fetch member for validation
  SELECT * INTO v_member FROM public.members WHERE id = p_member_id;
  IF v_member IS NULL THEN
    RAISE EXCEPTION 'Member % not found', p_member_id
      USING ERRCODE = 'P0002';
  END IF;

  -- Set the user ID for the audit trigger
  IF p_performed_by IS NOT NULL THEN
    PERFORM set_config('app.current_user_id', p_performed_by::text, true);
  END IF;

  -- Delete child records that now use RESTRICT
  DELETE FROM public.member_roles WHERE member_id = p_member_id;
  DELETE FROM public.member_honors WHERE member_id = p_member_id;
  DELETE FROM public.sepa_mandates WHERE member_id = p_member_id;
  -- member_transfers: delete (the BEFORE DELETE trigger on members already snapshots everything)
  DELETE FROM public.member_transfers WHERE member_id = p_member_id;

  -- Now the hard delete triggers audit_member_before_hard_delete
  DELETE FROM public.members WHERE id = p_member_id;
END;
$$;

GRANT EXECUTE ON FUNCTION public.safe_delete_member(uuid, uuid) TO service_role;
-- Intentionally NOT granted to authenticated — super-admin only via admin client
