-- Migration: Fix enum literal validation errors in enqueue functions
--
-- Problem: PostgreSQL validates enum literals against the enum type at
-- execution time, even when no rows match. If a status value like 'closed'
-- or 'in_progress_dry_run' was added to the enum in a later migration that
-- hasn't been applied to a given deployment (e.g. self-hosted Docker), the
-- entire enqueue_all_notifications() call aborts with:
--   ERROR 22P02: invalid input value for enum <type>: "<value>"
-- This prevents ALL notification types from being enqueued, not just the one
-- that references the missing value.
--
-- Fix: cast the enum column to ::text before comparing. Text comparison
-- bypasses enum validation entirely and works regardless of which enum values
-- exist on any given deployment.
--
-- Affected functions and the risky literals:
--   enqueue_overtime_checkout_notifications  →  task_status 'closed'
--   enqueue_overtime_idle_notifications      →  it_service_request_status 'in_progress_dry_run'
--   enqueue_isr_event_notifications          →  it_service_request_status 'in_progress_dry_run'
--   enqueue_isr_evidence_notifications       →  it_service_request_status 'in_progress'  (safe but cast for consistency)

CREATE OR REPLACE FUNCTION public.enqueue_overtime_checkout_notifications()
RETURNS void LANGUAGE plpgsql AS $$
DECLARE
  rec RECORD;
  v_last_completed timestamptz;
BEGIN
  FOR rec IN
    SELECT ds.id AS schedule_id, ds.user_id, al.check_in_at
    FROM public.duty_schedules ds
    JOIN public.attendance_logs al ON al.duty_schedule_id = ds.id AND al.user_id = ds.user_id
    WHERE ds.shift_type = 'overtime'
      AND ds.status IN ('arrival', 'late')
      AND al.check_in_at IS NOT NULL
      AND al.check_out_at IS NULL
      AND al.check_in_at <= now() - interval '1 hour'
      AND NOT EXISTS (
        SELECT 1 FROM public.task_assignments ta
        JOIN public.tasks t ON t.id = ta.task_id
        WHERE ta.user_id = ds.user_id AND t.status::text = 'in_progress'
      )
  LOOP
    SELECT MAX(t.completed_at) INTO v_last_completed
    FROM public.task_assignments ta
    JOIN public.tasks t ON t.id = ta.task_id
    WHERE ta.user_id = rec.user_id
      AND t.status::text IN ('completed', 'closed')
      AND t.completed_at IS NOT NULL
      AND t.completed_at >= rec.check_in_at;

    IF v_last_completed IS NOT NULL AND v_last_completed <= now() - interval '30 minutes' THEN
      INSERT INTO public.scheduled_notifications
        (schedule_id, user_id, notify_type, scheduled_for)
      VALUES
        (rec.schedule_id, rec.user_id, 'overtime_checkout_30', now())
      ON CONFLICT DO NOTHING;
    END IF;
  END LOOP;
END;
$$;

CREATE OR REPLACE FUNCTION public.enqueue_overtime_idle_notifications()
RETURNS void LANGUAGE plpgsql AS $$
DECLARE
  rec RECORD;
BEGIN
  FOR rec IN
    SELECT ds.id AS schedule_id, ds.user_id
    FROM public.duty_schedules ds
    JOIN public.attendance_logs al ON al.duty_schedule_id = ds.id AND al.user_id = ds.user_id
    WHERE ds.shift_type = 'overtime'
      AND ds.status IN ('arrival', 'late')
      AND al.check_in_at IS NOT NULL
      AND al.check_out_at IS NULL
      AND al.check_in_at <= now() - interval '15 minutes'
      AND NOT EXISTS (
        SELECT 1 FROM public.task_assignments ta
        JOIN public.tasks t ON t.id = ta.task_id
        WHERE ta.user_id = ds.user_id AND t.status::text = 'in_progress'
      )
      AND NOT EXISTS (
        SELECT 1 FROM public.it_service_request_assignments isra
        JOIN public.it_service_requests isr ON isr.id = isra.request_id
        WHERE isra.user_id = ds.user_id
          AND isr.status::text IN ('in_progress', 'in_progress_dry_run')
      )
  LOOP
    INSERT INTO public.scheduled_notifications
      (schedule_id, user_id, notify_type, scheduled_for)
    VALUES
      (rec.schedule_id, rec.user_id, 'overtime_idle_15', now())
    ON CONFLICT DO NOTHING;
  END LOOP;
END;
$$;

CREATE OR REPLACE FUNCTION public.enqueue_isr_event_notifications()
RETURNS void LANGUAGE plpgsql AS $$
DECLARE
  rec RECORD;
BEGIN
  FOR rec IN
    SELECT isr.id AS request_id, isr.event_date, isra.user_id
    FROM public.it_service_requests isr
    JOIN public.it_service_request_assignments isra ON isra.request_id = isr.id
    WHERE isr.status::text IN ('scheduled', 'in_progress_dry_run')
      AND isr.event_date IS NOT NULL
      AND isr.event_date BETWEEN now() + interval '60 minutes' - interval '90 seconds'
                              AND now() + interval '60 minutes' + interval '90 seconds'
  LOOP
    INSERT INTO public.scheduled_notifications
      (it_service_request_id, user_id, notify_type, scheduled_for)
    VALUES
      (rec.request_id, rec.user_id, 'isr_event_60', rec.event_date - interval '1 hour')
    ON CONFLICT DO NOTHING;
  END LOOP;
END;
$$;

CREATE OR REPLACE FUNCTION public.enqueue_isr_evidence_notifications()
RETURNS void LANGUAGE plpgsql AS $$
DECLARE
  rec RECORD;
  v_today_doy int := EXTRACT(DOY FROM now())::int;
BEGIN
  FOR rec IN
    SELECT isr.id AS request_id, isra.user_id
    FROM public.it_service_requests isr
    JOIN public.it_service_request_assignments isra ON isra.request_id = isr.id
    WHERE isr.status::text IN ('completed', 'in_progress')
      AND (
        NOT EXISTS (
          SELECT 1 FROM public.it_service_request_evidence e
          WHERE e.request_id = isr.id AND e.user_id = isra.user_id
        )
        OR
        NOT EXISTS (
          SELECT 1 FROM public.it_service_request_actions a
          WHERE a.request_id = isr.id AND a.user_id = isra.user_id
            AND a.action_taken IS NOT NULL AND TRIM(a.action_taken) != ''
        )
      )
      AND EXISTS (
        SELECT 1 FROM public.attendance_logs al
        WHERE al.user_id = isra.user_id
          AND al.check_in_at::date = now()::date
      )
  LOOP
    INSERT INTO public.scheduled_notifications
      (it_service_request_id, user_id, notify_type, scheduled_for, epoch)
    VALUES
      (rec.request_id, rec.user_id, 'isr_evidence_daily', now(), v_today_doy)
    ON CONFLICT DO NOTHING;
  END LOOP;
END;
$$;
