-- =============================================================================
-- AgenciaPsi — Functions — Notificações
-- =============================================================================
-- cancel_notifications_on_opt_out, cancel_notifications_on_session_cancel,
-- cancel_patient_pending_notifications, cleanup_notification_queue,
-- notify_on_intake, notify_on_scheduling, notify_on_session_status,
-- populate_notification_queue, unstick_notification_queue
-- =============================================================================

CREATE FUNCTION public.cancel_notifications_on_opt_out() RETURNS trigger
    LANGUAGE plpgsql SECURITY DEFINER
    AS $$
BEGIN
  -- WhatsApp opt-out
  IF OLD.whatsapp_opt_in = true AND NEW.whatsapp_opt_in = false THEN
    PERFORM public.cancel_patient_pending_notifications(
      NEW.patient_id, 'whatsapp'
    );
  END IF;
  -- Email opt-out
  IF OLD.email_opt_in = true AND NEW.email_opt_in = false THEN
    PERFORM public.cancel_patient_pending_notifications(
      NEW.patient_id, 'email'
    );
  END IF;
  -- SMS opt-out
  IF OLD.sms_opt_in = true AND NEW.sms_opt_in = false THEN
    PERFORM public.cancel_patient_pending_notifications(
      NEW.patient_id, 'sms'
    );
  END IF;
  RETURN NEW;
END;
$$;


ALTER FUNCTION public.cancel_notifications_on_opt_out() OWNER TO supabase_admin;

--
-- Name: cancel_notifications_on_session_cancel(); Type: FUNCTION; Schema: public; Owner: supabase_admin
--

CREATE FUNCTION public.cancel_notifications_on_session_cancel() RETURNS trigger
    LANGUAGE plpgsql SECURITY DEFINER
    AS $$
BEGIN
  IF NEW.status IN ('cancelado', 'excluido')
     AND OLD.status NOT IN ('cancelado', 'excluido')
  THEN
    PERFORM public.cancel_patient_pending_notifications(
      NEW.patient_id, NULL, NEW.id
    );
  END IF;
  RETURN NEW;
END;
$$;


ALTER FUNCTION public.cancel_notifications_on_session_cancel() OWNER TO supabase_admin;

--
-- Name: cancel_patient_pending_notifications(uuid, text, uuid); Type: FUNCTION; Schema: public; Owner: supabase_admin
--

CREATE FUNCTION public.cancel_patient_pending_notifications(p_patient_id uuid, p_channel text DEFAULT NULL::text, p_evento_id uuid DEFAULT NULL::uuid) RETURNS integer
    LANGUAGE plpgsql SECURITY DEFINER
    AS $$
DECLARE
  v_canceled integer;
BEGIN
  UPDATE public.notification_queue
  SET status = 'cancelado',
      updated_at = now()
  WHERE patient_id = p_patient_id
    AND status IN ('pendente', 'processando')
    AND (p_channel IS NULL OR channel = p_channel)
    AND (p_evento_id IS NULL OR agenda_evento_id = p_evento_id);

  GET DIAGNOSTICS v_canceled = ROW_COUNT;
  RETURN v_canceled;
END;
$$;


ALTER FUNCTION public.cancel_patient_pending_notifications(p_patient_id uuid, p_channel text, p_evento_id uuid) OWNER TO supabase_admin;

--
-- Name: cancel_recurrence_from(uuid, date); Type: FUNCTION; Schema: public; Owner: supabase_admin
--

CREATE FUNCTION public.cancel_recurrence_from(p_recurrence_id uuid, p_from_date date) RETURNS void
CREATE FUNCTION public.cancel_patient_pending_notifications(p_patient_id uuid, p_channel text DEFAULT NULL::text, p_evento_id uuid DEFAULT NULL::uuid) RETURNS integer
    LANGUAGE plpgsql SECURITY DEFINER
    AS $$
DECLARE
  v_canceled integer;
BEGIN
  UPDATE public.notification_queue
  SET status = 'cancelado',
      updated_at = now()
  WHERE patient_id = p_patient_id
    AND status IN ('pendente', 'processando')
    AND (p_channel IS NULL OR channel = p_channel)
    AND (p_evento_id IS NULL OR agenda_evento_id = p_evento_id);

  GET DIAGNOSTICS v_canceled = ROW_COUNT;
  RETURN v_canceled;
END;
$$;


ALTER FUNCTION public.cancel_patient_pending_notifications(p_patient_id uuid, p_channel text, p_evento_id uuid) OWNER TO supabase_admin;

--
-- Name: cancel_recurrence_from(uuid, date); Type: FUNCTION; Schema: public; Owner: supabase_admin
--

CREATE FUNCTION public.cancel_recurrence_from(p_recurrence_id uuid, p_from_date date) RETURNS void
CREATE FUNCTION public.cleanup_notification_queue() RETURNS integer
    LANGUAGE plpgsql SECURITY DEFINER
    AS $$
DECLARE
  v_deleted integer;
BEGIN
  DELETE FROM public.notification_queue
  WHERE status IN ('enviado', 'cancelado', 'ignorado')
    AND created_at < now() - interval '90 days';

  GET DIAGNOSTICS v_deleted = ROW_COUNT;
  RETURN v_deleted;
END;
$$;


ALTER FUNCTION public.cleanup_notification_queue() OWNER TO supabase_admin;

--
-- Name: create_clinic_tenant(text); Type: FUNCTION; Schema: public; Owner: supabase_admin
--

CREATE FUNCTION public.create_clinic_tenant(p_name text) RETURNS uuid
    LANGUAGE plpgsql SECURITY DEFINER
    AS $$
declare
  v_uid uuid;
  v_tenant uuid;
  v_name text;
begin
  v_uid := auth.uid();
  if v_uid is null then
    raise exception 'Not authenticated';
  end if;

  v_name := nullif(trim(coalesce(p_name, '')), '');
  if v_name is null then
    v_name := 'Clínica';
  end if;

  insert into public.tenants (name, kind, created_at)
  values (v_name, 'clinic', now())
  returning id into v_tenant;

  insert into public.tenant_members (tenant_id, user_id, role, status, created_at)
  values (v_tenant, v_uid, 'tenant_admin', 'active', now());

  return v_tenant;
end;
$$;


ALTER FUNCTION public.create_clinic_tenant(p_name text) OWNER TO supabase_admin;

--
-- Name: financial_records; Type: TABLE; Schema: public; Owner: supabase_admin
--

CREATE TABLE public.financial_records (
CREATE FUNCTION public.notify_on_intake() RETURNS trigger
    LANGUAGE plpgsql SECURITY DEFINER
    AS $$
BEGIN
  IF NEW.status = 'new' THEN
    INSERT INTO public.notifications (
      owner_id,
      tenant_id,
      type,
      ref_id,
      ref_table,
      payload
    )
    VALUES (
      NEW.owner_id,
      NEW.tenant_id,
      'new_patient',
      NEW.id,
      'patient_intake_requests',
      jsonb_build_object(
        'title',  'Novo cadastro externo',
        'detail', COALESCE(NEW.nome_completo, 'Paciente'),
        'deeplink', '/therapist/patients/cadastro/recebidos',
        'avatar_initials', upper(left(COALESCE(NEW.nome_completo, '?'), 2))
      )
    );
  END IF;
  RETURN NEW;
END;
$$;


ALTER FUNCTION public.notify_on_intake() OWNER TO supabase_admin;

--
-- Name: notify_on_scheduling(); Type: FUNCTION; Schema: public; Owner: supabase_admin
--

CREATE FUNCTION public.notify_on_scheduling() RETURNS trigger
    LANGUAGE plpgsql SECURITY DEFINER
    AS $$                                                                                                                   BEGIN                                                                                                                     IF NEW.status = 'pendente' THEN
      INSERT INTO public.notifications (                                                                                        owner_id,                                                                                                               tenant_id,                                                                                                              type,                                                                                                                   ref_id,                                                                                                                 ref_table,                                                                                                              payload                                                                                                               )                                                                                                                       VALUES (
        NEW.owner_id,                                                                                                           NEW.tenant_id,
        'new_scheduling',                                                                                                       NEW.id,                                                                                                                 'agendador_solicitacoes',                                                                                               jsonb_build_object(                                                                                                       'title',  'Nova solicitação de agendamento',                                                                            'detail', COALESCE(NEW.paciente_nome, 'Paciente') || ' ' || COALESCE(NEW.paciente_sobrenome, '') || ' — ' ||    COALESCE(NEW.tipo, ''),                                                                                                         'deeplink', '/therapist/agendamentos-recebidos',                                                                        'avatar_initials', upper(left(COALESCE(NEW.paciente_nome, '?'), 1) || left(COALESCE(NEW.paciente_sobrenome,     ''), 1))                                                                                                                      )                                                                                                                     );                                                                                                                    END IF;                                                                                                                 RETURN NEW;                                                                                                           END;                                                                                                                    $$;


ALTER FUNCTION public.notify_on_scheduling() OWNER TO supabase_admin;

--
-- Name: notify_on_session_status(); Type: FUNCTION; Schema: public; Owner: supabase_admin
--

CREATE FUNCTION public.notify_on_session_status() RETURNS trigger
    LANGUAGE plpgsql SECURITY DEFINER
    AS $$
DECLARE
  v_nome text;
BEGIN
  IF NEW.status IN ('faltou', 'cancelado') AND OLD.status IS DISTINCT FROM NEW.status THEN

    SELECT nome_completo
      INTO v_nome
      FROM public.patients
     WHERE id = NEW.patient_id
     LIMIT 1;

    INSERT INTO public.notifications (
      owner_id,
      tenant_id,
      type,
      ref_id,
      ref_table,
      payload
    )
    VALUES (
      NEW.owner_id,
      NEW.tenant_id,
      'session_status',
      NEW.id,
      'agenda_eventos',
      jsonb_build_object(
        'title',           CASE WHEN NEW.status = 'faltou' THEN 'Paciente faltou' ELSE 'Sessão cancelada' END,
        'detail',          COALESCE(v_nome, 'Paciente') || ' — ' || to_char(NEW.inicio_em, 'DD/MM HH24:MI'),
        'deeplink',        '/therapist/agenda',
        'avatar_initials', upper(left(COALESCE(v_nome, '?'), 2))
      )
    );

  END IF;
  RETURN NEW;
END;
$$;


ALTER FUNCTION public.notify_on_session_status() OWNER TO supabase_admin;

--
-- Name: on_new_user_seed_patient_groups(); Type: FUNCTION; Schema: public; Owner: supabase_admin
--

CREATE FUNCTION public.on_new_user_seed_patient_groups() RETURNS trigger
CREATE FUNCTION public.populate_notification_queue() RETURNS void
    LANGUAGE plpgsql SECURITY DEFINER
    AS $$
BEGIN
  INSERT INTO public.notification_queue (
    tenant_id, owner_id, agenda_evento_id, patient_id,
    channel, template_key, schedule_key,
    resolved_vars, recipient_address,
    scheduled_at, idempotency_key
  )
  SELECT
    ae.tenant_id,
    ae.owner_id,
    ae.id AS agenda_evento_id,
    ae.patient_id,
    ch.channel,
    'session.' || REPLACE(ns.event_type, '_sessao', '') || '.' || ch.channel,
    ns.schedule_key,
    jsonb_build_object(
      'nome_paciente',   COALESCE(p.nome_completo, 'Paciente'),
      'data_sessao',     TO_CHAR(ae.inicio_em AT TIME ZONE 'America/Sao_Paulo', 'DD/MM/YYYY'),
      'hora_sessao',     TO_CHAR(ae.inicio_em AT TIME ZONE 'America/Sao_Paulo', 'HH24:MI'),
      'nome_terapeuta',  COALESCE(prof.full_name, 'Terapeuta'),
      'modalidade',      COALESCE(ae.modalidade, 'Presencial'),
      'titulo',          COALESCE(ae.titulo, 'Sessão')
    ),
    CASE ch.channel
      WHEN 'whatsapp' THEN COALESCE(p.telefone, '')
      WHEN 'sms'      THEN COALESCE(p.telefone, '')
      WHEN 'email'    THEN COALESCE(p.email_principal, '')
    END,
    CASE
      WHEN (ae.inicio_em - (ns.offset_minutes || ' minutes')::interval)::time
           < ns.allowed_time_start
      THEN DATE_TRUNC('day', ae.inicio_em - (ns.offset_minutes || ' minutes')::interval)
           + ns.allowed_time_start
      WHEN (ae.inicio_em - (ns.offset_minutes || ' minutes')::interval)::time
           > ns.allowed_time_end
      THEN DATE_TRUNC('day', ae.inicio_em - (ns.offset_minutes || ' minutes')::interval)
           + ns.allowed_time_start
      ELSE ae.inicio_em - (ns.offset_minutes || ' minutes')::interval
    END,
    ae.id::text || ':' || ns.schedule_key || ':' || ch.channel || ':'
      || ae.inicio_em::date::text
  FROM public.agenda_eventos ae
  JOIN public.patients p ON p.id = ae.patient_id
  LEFT JOIN public.profiles prof ON prof.id = ae.owner_id
  JOIN public.notification_schedules ns
    ON ns.owner_id = ae.owner_id
    AND ns.is_active = true
    AND ns.deleted_at IS NULL
    AND ns.trigger_type = 'before_event'
    AND ns.event_type = 'lembrete_sessao'
  JOIN public.notification_channels nc
    ON nc.owner_id = ae.owner_id
    AND nc.is_active = true
    AND nc.deleted_at IS NULL
  CROSS JOIN LATERAL (
    SELECT 'whatsapp' AS channel WHERE ns.whatsapp_enabled AND nc.channel = 'whatsapp'
    UNION ALL
    SELECT 'email'    AS channel WHERE ns.email_enabled    AND nc.channel = 'email'
    UNION ALL
    SELECT 'sms'      AS channel WHERE ns.sms_enabled      AND nc.channel = 'sms'
  ) ch
  LEFT JOIN public.notification_preferences np
    ON np.patient_id = ae.patient_id
    AND np.owner_id = ae.owner_id
    AND np.deleted_at IS NULL
  WHERE
    ae.inicio_em > now()
    AND ae.inicio_em <= now() + interval '48 hours'
    AND ae.status NOT IN ('cancelado', 'faltou')
    AND CASE ch.channel
          WHEN 'whatsapp' THEN COALESCE(p.telefone, '') != ''
          WHEN 'sms'      THEN COALESCE(p.telefone, '') != ''
          WHEN 'email'    THEN COALESCE(p.email_principal, '') != ''
        END
    AND CASE ch.channel
          WHEN 'whatsapp' THEN COALESCE(np.whatsapp_opt_in, true)
          WHEN 'email'    THEN COALESCE(np.email_opt_in, true)
          WHEN 'sms'      THEN COALESCE(np.sms_opt_in, false)
        END
    AND EXISTS (
      SELECT 1 FROM public.profiles tp
      WHERE tp.id = ae.owner_id
      AND COALESCE(tp.notify_reminders, true) = true
    )
  ON CONFLICT (idempotency_key) DO NOTHING;
END;
$$;


ALTER FUNCTION public.populate_notification_queue() OWNER TO supabase_admin;

--
-- Name: prevent_promoting_to_system(); Type: FUNCTION; Schema: public; Owner: supabase_admin
--

CREATE FUNCTION public.prevent_promoting_to_system() RETURNS trigger
CREATE FUNCTION public.unstick_notification_queue() RETURNS integer
    LANGUAGE plpgsql SECURITY DEFINER
    AS $$
DECLARE
  v_unstuck integer;
BEGIN
  UPDATE public.notification_queue
  SET status = 'pendente',
      attempts = attempts + 1,
      last_error = 'Timeout: preso em processando por >10min',
      next_retry_at = now() + interval '2 minutes'
  WHERE status = 'processando'
    AND updated_at < now() - interval '10 minutes';

  GET DIAGNOSTICS v_unstuck = ROW_COUNT;
  RETURN v_unstuck;
END;
$$;


ALTER FUNCTION public.unstick_notification_queue() OWNER TO supabase_admin;

--
-- Name: update_payment_settings_updated_at(); Type: FUNCTION; Schema: public; Owner: supabase_admin
--

CREATE FUNCTION public.update_payment_settings_updated_at() RETURNS trigger
