-- =============================================================================
-- F6.2 Lote G — funções SQL puras → plpgsql + roteamento por tenant
--
-- ⚠️ APLICAR COMO supabase_admin.
--
-- SQL puro não permite set_config dinâmico do search_path (limitação 3 do
-- blueprint) → converter pra plpgsql. Adicionam p_tenant_id + _tenant_route.
-- RETURNS SETOF <tabela_tenant> → jsonb. get_entity_primary_phone (interno,
-- 0 callers) herda search_path do chamador (sem SET, unqualified).
-- =============================================================================

BEGIN;

DROP FUNCTION IF EXISTS public.get_financial_summary(uuid, integer, integer);
DROP FUNCTION IF EXISTS public.get_financial_summary(uuid, uuid, integer, integer);
CREATE FUNCTION public.get_financial_summary(p_tenant_id uuid, p_owner_id uuid, p_year integer, p_month integer)
RETURNS TABLE(total_receitas numeric, total_despesas numeric, total_pendente numeric, saldo_liquido numeric, total_repasse numeric, count_receitas bigint, count_despesas bigint)
LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public','pg_temp'
AS $$
BEGIN
    PERFORM set_config('search_path', public._tenant_route(p_tenant_id) || ',public,pg_temp', true);
    RETURN QUERY
    SELECT
        COALESCE(SUM(amount) FILTER (WHERE type='receita' AND status='paid'), 0),
        COALESCE(SUM(amount) FILTER (WHERE type='despesa' AND status='paid'), 0),
        COALESCE(SUM(amount) FILTER (WHERE status IN ('pending','overdue')), 0),
        COALESCE(SUM(amount) FILTER (WHERE type='receita' AND status='paid'), 0) - COALESCE(SUM(amount) FILTER (WHERE type='despesa' AND status='paid'), 0),
        COALESCE(SUM(clinic_fee_amount) FILTER (WHERE type='receita' AND status='paid'), 0),
        COUNT(*) FILTER (WHERE type='receita' AND deleted_at IS NULL),
        COUNT(*) FILTER (WHERE type='despesa' AND deleted_at IS NULL)
    FROM financial_records
    WHERE owner_id = p_owner_id AND deleted_at IS NULL
      AND EXTRACT(YEAR FROM COALESCE(paid_at::date, due_date, created_at::date)) = p_year
      AND EXTRACT(MONTH FROM COALESCE(paid_at::date, due_date, created_at::date)) = p_month;
END $$;

-- list_financial_records: RETURNS SETOF financial_records → jsonb (array)
DROP FUNCTION IF EXISTS public.list_financial_records(uuid, integer, integer, text, text, uuid, integer, integer);
DROP FUNCTION IF EXISTS public.list_financial_records(uuid, uuid, integer, integer, text, text, uuid, integer, integer);
CREATE FUNCTION public.list_financial_records(p_tenant_id uuid, p_owner_id uuid, p_year integer DEFAULT NULL, p_month integer DEFAULT NULL, p_type text DEFAULT NULL, p_status text DEFAULT NULL, p_patient_id uuid DEFAULT NULL, p_limit integer DEFAULT 50, p_offset integer DEFAULT 0)
RETURNS jsonb LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public','pg_temp'
AS $$
DECLARE v_result jsonb;
BEGIN
    PERFORM set_config('search_path', public._tenant_route(p_tenant_id) || ',public,pg_temp', true);
    SELECT COALESCE(jsonb_agg(row_json), '[]'::jsonb) INTO v_result FROM (
        SELECT to_jsonb(fr) AS row_json
        FROM financial_records fr
        WHERE fr.owner_id = p_owner_id AND fr.deleted_at IS NULL
          AND (p_type IS NULL OR fr.type::text = p_type)
          AND (p_status IS NULL OR fr.status = p_status)
          AND (p_patient_id IS NULL OR fr.patient_id = p_patient_id)
          AND (p_year IS NULL OR EXTRACT(YEAR FROM COALESCE(fr.paid_at::date, fr.due_date, fr.created_at::date)) = p_year)
          AND (p_month IS NULL OR EXTRACT(MONTH FROM COALESCE(fr.paid_at::date, fr.due_date, fr.created_at::date)) = p_month)
        ORDER BY COALESCE(fr.paid_at, fr.due_date::timestamptz, fr.created_at) DESC
        LIMIT p_limit OFFSET p_offset
    ) sub;
    RETURN v_result;
END $$;

DROP FUNCTION IF EXISTS public.get_patient_session_counts(uuid[]);
DROP FUNCTION IF EXISTS public.get_patient_session_counts(uuid, uuid[]);
CREATE FUNCTION public.get_patient_session_counts(p_tenant_id uuid, p_patient_ids uuid[])
RETURNS TABLE(patient_id uuid, session_count integer, last_session_at timestamptz)
LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public','pg_temp'
AS $$
BEGIN
    PERFORM set_config('search_path', public._tenant_route(p_tenant_id) || ',public,pg_temp', true);
    RETURN QUERY
    SELECT ae.patient_id, COUNT(*)::int, MAX(ae.inicio_em)
    FROM agenda_eventos ae
    WHERE ae.patient_id = ANY(p_patient_ids)
    GROUP BY ae.patient_id;
END $$;

DROP FUNCTION IF EXISTS public.get_financial_report(uuid, date, date, text);
DROP FUNCTION IF EXISTS public.get_financial_report(uuid, uuid, date, date, text);
CREATE FUNCTION public.get_financial_report(p_tenant_id uuid, p_owner_id uuid, p_start_date date, p_end_date date, p_group_by text DEFAULT 'month')
RETURNS TABLE(group_key text, group_label text, total_receitas numeric, total_despesas numeric, saldo numeric, total_pendente numeric, total_overdue numeric, count_records bigint)
LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public','pg_temp'
AS $$
BEGIN
    PERFORM set_config('search_path', public._tenant_route(p_tenant_id) || ',public,pg_temp', true);
    RETURN QUERY
    WITH base AS (
        SELECT fr.type, fr.amount, fr.final_amount, fr.status, fr.deleted_at,
            CASE p_group_by
                WHEN 'month' THEN TO_CHAR(COALESCE(fr.paid_at::date, fr.due_date, fr.created_at::date),'YYYY-MM')
                WHEN 'week' THEN TO_CHAR(COALESCE(fr.paid_at::date, fr.due_date, fr.created_at::date),'IYYY-"W"IW')
                WHEN 'category' THEN COALESCE(fr.category_id::text, fr.category, 'sem_categoria')
                WHEN 'patient' THEN COALESCE(fr.patient_id::text, 'sem_paciente')
                ELSE NULL END AS gkey,
            CASE p_group_by
                WHEN 'month' THEN TO_CHAR(COALESCE(fr.paid_at::date, fr.due_date, fr.created_at::date),'YYYY-MM')
                WHEN 'week' THEN TO_CHAR(COALESCE(fr.paid_at::date, fr.due_date, fr.created_at::date),'IYYY-"W"IW')
                WHEN 'category' THEN COALESCE(fc.name, fr.category, 'Sem categoria')
                WHEN 'patient' THEN COALESCE(p.nome_completo, fr.patient_id::text, 'Sem paciente')
                ELSE NULL END AS glabel
        FROM financial_records fr
        LEFT JOIN financial_categories fc ON fc.id = fr.category_id
        LEFT JOIN patients p ON p.id = fr.patient_id
        WHERE fr.owner_id = p_owner_id AND fr.deleted_at IS NULL
          AND COALESCE(fr.paid_at::date, fr.due_date, fr.created_at::date) BETWEEN p_start_date AND p_end_date
    )
    SELECT gkey, glabel,
        COALESCE(SUM(final_amount) FILTER (WHERE type='receita' AND status='paid'),0),
        COALESCE(SUM(final_amount) FILTER (WHERE type='despesa' AND status='paid'),0),
        COALESCE(SUM(final_amount) FILTER (WHERE type='receita' AND status='paid'),0) - COALESCE(SUM(final_amount) FILTER (WHERE type='despesa' AND status='paid'),0),
        COALESCE(SUM(final_amount) FILTER (WHERE status='pending'),0),
        COALESCE(SUM(final_amount) FILTER (WHERE status='overdue'),0),
        COUNT(*)
    FROM base WHERE gkey IS NOT NULL GROUP BY gkey, glabel ORDER BY gkey ASC;
END $$;

-- get_entity_primary_phone: interno (0 callers). Sem SET search_path → herda do
-- chamador (que roteia pro schema). Unqualified. Mantém assinatura.
CREATE OR REPLACE FUNCTION public.get_entity_primary_phone(p_entity_type text, p_entity_id uuid)
RETURNS text LANGUAGE sql STABLE SECURITY DEFINER
AS $$
    SELECT number FROM contact_phones
    WHERE entity_type = p_entity_type AND entity_id = p_entity_id
    ORDER BY is_primary DESC, position ASC, created_at ASC
    LIMIT 1;
$$;

COMMIT;
