-- =====================================================
-- Waitlist Management
--
-- A) Course cancellation with automatic waitlist promotion
-- B) Event cancellation with automatic waitlist promotion
--
-- When an enrolled/confirmed participant is cancelled,
-- the oldest waitlisted entry is atomically promoted.
-- =====================================================

-- -------------------------------------------------------
-- A) Course waitlist promotion
-- -------------------------------------------------------

CREATE OR REPLACE FUNCTION public.cancel_course_enrollment(p_participant_id uuid)
RETURNS jsonb
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = ''
AS $$
DECLARE
  v_participant record;
  v_course record;
  v_promoted_id uuid;
  v_promoted_name text;
BEGIN
  -- Lock participant
  SELECT * INTO v_participant
  FROM public.course_participants
  WHERE id = p_participant_id
  FOR UPDATE;

  IF v_participant IS NULL THEN
    RAISE EXCEPTION 'Teilnehmer nicht gefunden'
      USING ERRCODE = 'P0002';
  END IF;

  -- Lock course
  SELECT * INTO v_course
  FROM public.courses
  WHERE id = v_participant.course_id
  FOR UPDATE;

  -- Cancel
  UPDATE public.course_participants
  SET status = 'cancelled'::public.enrollment_status,
      cancelled_at = now()
  WHERE id = p_participant_id;

  -- If was enrolled (not already waitlisted/cancelled), promote oldest waitlisted
  IF v_participant.status = 'enrolled' THEN
    UPDATE public.course_participants
    SET status = 'enrolled'::public.enrollment_status
    WHERE id = (
      SELECT id FROM public.course_participants
      WHERE course_id = v_participant.course_id
        AND status = 'waitlisted'
      ORDER BY enrolled_at ASC
      LIMIT 1
      FOR UPDATE SKIP LOCKED
    )
    RETURNING id, first_name || ' ' || last_name
      INTO v_promoted_id, v_promoted_name;
  END IF;

  RETURN jsonb_build_object(
    'cancelled_id', p_participant_id,
    'promoted_id', v_promoted_id,
    'promoted_name', v_promoted_name
  );
END;
$$;

GRANT EXECUTE ON FUNCTION public.cancel_course_enrollment(uuid) TO authenticated;
GRANT EXECUTE ON FUNCTION public.cancel_course_enrollment(uuid) TO service_role;

-- -------------------------------------------------------
-- B) Event registration cancellation + waitlist promotion
-- -------------------------------------------------------

-- Add updated_at column if not present
ALTER TABLE public.event_registrations
  ADD COLUMN IF NOT EXISTS updated_at timestamptz DEFAULT now();

CREATE OR REPLACE FUNCTION public.cancel_event_registration(p_registration_id uuid)
RETURNS jsonb
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = ''
AS $$
DECLARE
  v_registration record;
  v_event record;
  v_promoted_id uuid;
  v_promoted_name text;
BEGIN
  -- Lock registration
  SELECT * INTO v_registration
  FROM public.event_registrations
  WHERE id = p_registration_id
  FOR UPDATE;

  IF v_registration IS NULL THEN
    RAISE EXCEPTION 'Anmeldung nicht gefunden'
      USING ERRCODE = 'P0002';
  END IF;

  -- Lock event
  SELECT * INTO v_event
  FROM public.events
  WHERE id = v_registration.event_id
  FOR UPDATE;

  -- Cancel
  UPDATE public.event_registrations
  SET status = 'cancelled',
      updated_at = now()
  WHERE id = p_registration_id;

  -- If was confirmed or pending, promote oldest waitlisted
  IF v_registration.status IN ('confirmed', 'pending') THEN
    UPDATE public.event_registrations
    SET status = 'confirmed',
        updated_at = now()
    WHERE id = (
      SELECT id FROM public.event_registrations
      WHERE event_id = v_registration.event_id
        AND status = 'waitlisted'
      ORDER BY created_at ASC
      LIMIT 1
      FOR UPDATE SKIP LOCKED
    )
    RETURNING id, first_name || ' ' || last_name
      INTO v_promoted_id, v_promoted_name;
  END IF;

  RETURN jsonb_build_object(
    'cancelled_id', p_registration_id,
    'promoted_id', v_promoted_id,
    'promoted_name', v_promoted_name
  );
END;
$$;

GRANT EXECUTE ON FUNCTION public.cancel_event_registration(uuid) TO authenticated;
GRANT EXECUTE ON FUNCTION public.cancel_event_registration(uuid) TO service_role;
