-- =============================================================================
-- Migration: 20260420000004_lgpd_export_patient_rpc
-- Sessao 11 - Fase 2b (Opcao C).
--
-- Implementa LGPD Art. 18 - direito de portabilidade do titular.
-- RPC export_patient_data(p_patient_id uuid) retorna jsonb com todos os dados
-- relacionados ao paciente. Registra o evento em audit_logs para rastreabilidade.
--
-- Seguranca:
--   - SECURITY DEFINER permite agregar tabelas diversas bypassando RLS
--   - Verificacao explicita: caller deve ser tenant_member ativo da clinica do paciente
--   - Proibido acesso cross-tenant
-- =============================================================================

CREATE OR REPLACE FUNCTION public.export_patient_data(p_patient_id UUID)
RETURNS JSONB
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public, pg_temp
AS $$
DECLARE
    v_patient RECORD;
    v_tenant_id UUID;
    v_caller UUID;
    v_is_member BOOLEAN;
    v_result JSONB;
BEGIN
    v_caller := auth.uid();
    IF v_caller IS NULL THEN
        RAISE EXCEPTION 'Autenticacao obrigatoria' USING ERRCODE = '28000';
    END IF;

    -- carrega paciente
    SELECT * INTO v_patient FROM public.patients WHERE id = p_patient_id;
    IF NOT FOUND THEN
        RAISE EXCEPTION 'Paciente nao encontrado' USING ERRCODE = 'P0002';
    END IF;

    v_tenant_id := v_patient.tenant_id;

    -- verifica se caller e membro ativo do tenant do paciente
    SELECT EXISTS (
        SELECT 1 FROM public.tenant_members tm
        WHERE tm.tenant_id = v_tenant_id
          AND tm.user_id = v_caller
          AND tm.status = 'active'
    ) OR public.is_saas_admin() INTO v_is_member;

    IF NOT v_is_member THEN
        RAISE EXCEPTION 'Sem permissao para exportar dados deste paciente' USING ERRCODE = '42501';
    END IF;

    -- monta o payload
    v_result := jsonb_build_object(
        'export_metadata', jsonb_build_object(
            'generated_at', now(),
            'generated_by', v_caller,
            'tenant_id', v_tenant_id,
            'patient_id', p_patient_id,
            'lgpd_basis', 'Art. 18, II - portabilidade dos dados do titular',
            'controller', 'AgenciaPSI - Clinica responsavel',
            'format_version', '1.0'
        ),
        'paciente', to_jsonb(v_patient),
        'contatos', COALESCE((
            SELECT jsonb_agg(to_jsonb(pc) ORDER BY pc.created_at)
            FROM public.patient_contacts pc
            WHERE pc.patient_id = p_patient_id
        ), '[]'::jsonb),
        'contatos_apoio', COALESCE((
            SELECT jsonb_agg(to_jsonb(psc) ORDER BY psc.created_at)
            FROM public.patient_support_contacts psc
            WHERE psc.patient_id = p_patient_id
        ), '[]'::jsonb),
        'historico_status', COALESCE((
            SELECT jsonb_agg(to_jsonb(psh) ORDER BY psh.alterado_em)
            FROM public.patient_status_history psh
            WHERE psh.patient_id = p_patient_id
        ), '[]'::jsonb),
        'timeline', COALESCE((
            SELECT jsonb_agg(to_jsonb(pt) ORDER BY pt.ocorrido_em)
            FROM public.patient_timeline pt
            WHERE pt.patient_id = p_patient_id
        ), '[]'::jsonb),
        'descontos', COALESCE((
            SELECT jsonb_agg(to_jsonb(pd) ORDER BY pd.created_at)
            FROM public.patient_discounts pd
            WHERE pd.patient_id = p_patient_id
        ), '[]'::jsonb),
        'eventos_agenda', COALESCE((
            SELECT jsonb_agg(
                jsonb_build_object(
                    'id', ae.id,
                    'tipo', ae.tipo,
                    'inicio_em', ae.inicio_em,
                    'fim_em', ae.fim_em,
                    'status', ae.status,
                    'observacoes', ae.observacoes,
                    'created_at', ae.created_at
                ) ORDER BY ae.inicio_em
            )
            FROM public.agenda_eventos ae
            WHERE ae.patient_id = p_patient_id
        ), '[]'::jsonb),
        'registros_financeiros', COALESCE((
            SELECT jsonb_agg(
                jsonb_build_object(
                    'id', fr.id,
                    'amount', fr.amount,
                    'discount_amount', fr.discount_amount,
                    'final_amount', fr.final_amount,
                    'status', fr.status,
                    'due_date', fr.due_date,
                    'paid_at', fr.paid_at,
                    'payment_method', fr.payment_method,
                    'notes', fr.notes,
                    'created_at', fr.created_at
                ) ORDER BY fr.created_at
            )
            FROM public.financial_records fr
            WHERE fr.patient_id = p_patient_id
        ), '[]'::jsonb),
        'documentos', COALESCE((
            SELECT jsonb_agg(
                jsonb_build_object(
                    'id', d.id,
                    'nome_original', d.nome_original,
                    'tipo_documento', d.tipo_documento,
                    'categoria', d.categoria,
                    'descricao', d.descricao,
                    'mime_type', d.mime_type,
                    'tamanho_bytes', d.tamanho_bytes,
                    'status_revisao', d.status_revisao,
                    'visibilidade', d.visibilidade,
                    'uploaded_at', d.uploaded_at,
                    'created_at', d.created_at
                ) ORDER BY d.created_at
            )
            FROM public.documents d
            WHERE d.patient_id = p_patient_id AND d.deleted_at IS NULL
        ), '[]'::jsonb),
        'notificacoes_enviadas', COALESCE((
            SELECT jsonb_agg(
                jsonb_build_object(
                    'id', nl.id,
                    'channel', nl.channel,
                    'template_key', nl.template_key,
                    'recipient_address', nl.recipient_address,
                    'status', nl.status,
                    'sent_at', nl.sent_at,
                    'delivered_at', nl.delivered_at,
                    'read_at', nl.read_at,
                    'failure_reason', nl.failure_reason,
                    'created_at', nl.created_at
                ) ORDER BY nl.created_at
            )
            FROM public.notification_logs nl
            WHERE nl.patient_id = p_patient_id
        ), '[]'::jsonb),
        'audit_trail', COALESCE((
            SELECT jsonb_agg(
                jsonb_build_object(
                    'id', al.id,
                    'action', al.action,
                    'entity_type', al.entity_type,
                    'changed_fields', al.changed_fields,
                    'user_id', al.user_id,
                    'created_at', al.created_at
                ) ORDER BY al.created_at
            )
            FROM public.audit_logs al
            WHERE al.tenant_id = v_tenant_id
              AND al.entity_type = 'patients'
              AND al.entity_id = p_patient_id::text
        ), '[]'::jsonb),
        'acessos_a_documentos', COALESCE((
            SELECT jsonb_agg(
                jsonb_build_object(
                    'id', dal.id,
                    'documento_id', dal.documento_id,
                    'acao', dal.acao,
                    'user_id', dal.user_id,
                    'acessado_em', dal.acessado_em
                ) ORDER BY dal.acessado_em
            )
            FROM public.document_access_logs dal
            WHERE dal.documento_id IN (
                SELECT id FROM public.documents WHERE patient_id = p_patient_id
            )
        ), '[]'::jsonb),
        'grupos', COALESCE((
            SELECT jsonb_agg(jsonb_build_object('patient_group_id', pgp.patient_group_id))
            FROM public.patient_group_patient pgp
            WHERE pgp.patient_id = p_patient_id
        ), '[]'::jsonb),
        'tags', COALESCE((
            SELECT jsonb_agg(jsonb_build_object('tag_id', ppt.tag_id))
            FROM public.patient_patient_tag ppt
            WHERE ppt.patient_id = p_patient_id
        ), '[]'::jsonb)
    );

    -- registra o export como evento auditavel
    INSERT INTO public.audit_logs (
        tenant_id, user_id, entity_type, entity_id, action,
        old_values, new_values, changed_fields, metadata
    ) VALUES (
        v_tenant_id, v_caller, 'patients', p_patient_id::text, 'update',
        NULL, NULL, ARRAY['__lgpd_export__'],
        jsonb_build_object(
            'action_kind', 'lgpd_export',
            'lgpd_basis', 'Art. 18, II',
            'patient_name', v_patient.nome_completo
        )
    );

    RETURN v_result;
END;
$$;

COMMENT ON FUNCTION public.export_patient_data(UUID) IS
    'LGPD Art. 18, II - exporta todos os dados do paciente em jsonb portavel. Registra evento em audit_logs.';

REVOKE ALL ON FUNCTION public.export_patient_data(UUID) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.export_patient_data(UUID) TO authenticated;
