-- Add target_shift_id + snapshots to swap_requests, extend RPCs to support two-shift swaps

ALTER TABLE public.swap_requests
  ADD COLUMN IF NOT EXISTS target_shift_id uuid;

ALTER TABLE public.swap_requests
  ADD COLUMN IF NOT EXISTS target_shift_type text;

ALTER TABLE public.swap_requests
  ADD COLUMN IF NOT EXISTS target_shift_start_time timestamptz;

ALTER TABLE public.swap_requests
  ADD COLUMN IF NOT EXISTS target_reliever_ids uuid[] DEFAULT '{}'::uuid[];

-- Replace request_shift_swap to accept a target shift id and insert a notification
CREATE OR REPLACE FUNCTION public.request_shift_swap(
  p_shift_id uuid,
  p_target_shift_id uuid,
  p_recipient_id uuid
)
RETURNS uuid LANGUAGE plpgsql AS $$
DECLARE
  v_shift_record RECORD;
  v_target_shift RECORD;
  v_recipient RECORD;
  v_new_id uuid;
BEGIN
  -- shift must exist and be owned by caller
  SELECT * INTO v_shift_record FROM public.duty_schedules WHERE id = p_shift_id;
  IF NOT FOUND THEN
    RAISE EXCEPTION 'shift not found';
  END IF;
  IF v_shift_record.user_id <> auth.uid() THEN
    RAISE EXCEPTION 'permission denied: only shift owner may request swap';
  END IF;

  -- recipient must exist and be it_staff
  SELECT id, role INTO v_recipient FROM public.profiles WHERE id = p_recipient_id;
  IF NOT FOUND THEN
    RAISE EXCEPTION 'recipient not found';
  END IF;
  IF v_recipient.role <> 'it_staff' THEN
    RAISE EXCEPTION 'recipient must be it_staff';
  END IF;

  -- target shift must exist and be owned by recipient
  SELECT * INTO v_target_shift FROM public.duty_schedules WHERE id = p_target_shift_id;
  IF NOT FOUND THEN
    RAISE EXCEPTION 'target shift not found';
  END IF;
  IF v_target_shift.user_id <> p_recipient_id THEN
    RAISE EXCEPTION 'target shift not owned by recipient';
  END IF;

  INSERT INTO public.swap_requests(
      requester_id, recipient_id, shift_id, target_shift_id, status, created_at, updated_at,
      shift_type, shift_start_time, reliever_ids,
      target_shift_type, target_shift_start_time, target_reliever_ids
  )
  VALUES (
    auth.uid(), p_recipient_id, p_shift_id, p_target_shift_id, 'pending', now(), now(),
    v_shift_record.shift_type, v_shift_record.start_time, v_shift_record.reliever_ids,
    v_target_shift.shift_type, v_target_shift.start_time, v_target_shift.reliever_ids
  )
  RETURNING id INTO v_new_id;

  -- notify recipient about incoming swap request
  INSERT INTO public.notifications(user_id, actor_id, type, created_at)
  VALUES (p_recipient_id, auth.uid(), 'swap_request', now());

  RETURN v_new_id;
END;
$$;

-- Replace respond_shift_swap to swap both duty_schedules atomically on acceptance
CREATE OR REPLACE FUNCTION public.respond_shift_swap(p_swap_id uuid, p_action text)
RETURNS void LANGUAGE plpgsql AS $$
DECLARE
  v_swap RECORD;
BEGIN
  SELECT * INTO v_swap FROM public.swap_requests WHERE id = p_swap_id;
  IF NOT FOUND THEN
    RAISE EXCEPTION 'swap request not found';
  END IF;

  IF p_action NOT IN ('accepted','rejected','admin_review') THEN
    RAISE EXCEPTION 'invalid action';
  END IF;

  IF p_action = 'accepted' THEN
    -- only recipient or admin/dispatcher can accept
    IF NOT (
      v_swap.recipient_id = auth.uid()
      OR EXISTS (SELECT 1 FROM public.profiles p WHERE p.id = auth.uid() AND p.role IN ('admin','dispatcher'))
    ) THEN
      RAISE EXCEPTION 'permission denied';
    END IF;

    -- ensure both shifts are still owned by the expected users before swapping
    IF NOT EXISTS (SELECT 1 FROM public.duty_schedules WHERE id = v_swap.shift_id AND user_id = v_swap.requester_id) THEN
      RAISE EXCEPTION 'requester shift ownership changed, cannot accept swap';
    END IF;
    IF v_swap.target_shift_id IS NULL THEN
      RAISE EXCEPTION 'target shift missing';
    END IF;
    IF NOT EXISTS (SELECT 1 FROM public.duty_schedules WHERE id = v_swap.target_shift_id AND user_id = v_swap.recipient_id) THEN
      RAISE EXCEPTION 'target shift ownership changed, cannot accept swap';
    END IF;

    -- perform the swap (atomic within function)
    UPDATE public.duty_schedules
    SET user_id = v_swap.recipient_id
    WHERE id = v_swap.shift_id;

    UPDATE public.duty_schedules
    SET user_id = v_swap.requester_id
    WHERE id = v_swap.target_shift_id;

    UPDATE public.swap_requests
    SET status = 'accepted', updated_at = now()
    WHERE id = p_swap_id;

    -- record approver/participant
    INSERT INTO public.swap_request_participants(swap_request_id, user_id, role)
    VALUES (p_swap_id, auth.uid(), 'approver')
    ON CONFLICT DO NOTHING;

    -- notify requester about approval
    INSERT INTO public.notifications(user_id, actor_id, type, created_at)
    VALUES (v_swap.requester_id, auth.uid(), 'swap_update', now());

  ELSIF p_action = 'rejected' THEN
    -- only recipient or admin/dispatcher can reject
    IF NOT (
      v_swap.recipient_id = auth.uid()
      OR EXISTS (SELECT 1 FROM public.profiles p WHERE p.id = auth.uid() AND p.role IN ('admin','dispatcher'))
    ) THEN
      RAISE EXCEPTION 'permission denied';
    END IF;

    UPDATE public.swap_requests
    SET status = 'rejected', updated_at = now()
    WHERE id = p_swap_id;

    INSERT INTO public.swap_request_participants(swap_request_id, user_id, role)
    VALUES (p_swap_id, auth.uid(), 'approver')
    ON CONFLICT DO NOTHING;

    -- notify requester about rejection
    INSERT INTO public.notifications(user_id, actor_id, type, created_at)
    VALUES (v_swap.requester_id, auth.uid(), 'swap_update', now());

  ELSE -- admin_review
    -- only requester may escalate for admin review
    IF NOT (v_swap.requester_id = auth.uid()) THEN
      RAISE EXCEPTION 'permission denied';
    END IF;

    UPDATE public.swap_requests
    SET status = 'admin_review', updated_at = now()
    WHERE id = p_swap_id;

    -- notify recipient/requester about status change
    INSERT INTO public.notifications(user_id, actor_id, type, created_at)
    VALUES (v_swap.requester_id, auth.uid(), 'swap_update', now());
  END IF;
END;
$$;