/*
|--------------------------------------------------------------------------
| Agência PSI
|--------------------------------------------------------------------------
| Arquivo: src/features/patients/services/patientsRepository.js
| V#3 — fundação: queries de patients centralizadas.
|
| Mesmo padrão de feature/agenda/services/agendaRepository.js. Pages devem
| chamar este repo em vez de fazer supabase.from('patients') direto.
|--------------------------------------------------------------------------
*/
import { supabase } from '@/lib/supabase/client';
import { assertTenantId, getUid } from '@/features/agenda/services/_tenantGuards';

const PATIENTS_SELECT_BASE = `
    id, tenant_id, owner_id, user_id, responsible_member_id, therapist_member_id,
    nome_completo, email_principal, email_alternativo, telefone, telefone_alternativo,
    cpf, rg, data_nascimento, naturalidade, genero, estado_civil,
    profissao, escolaridade, status,
    cep, endereco, numero, bairro, complemento, cidade, estado, pais,
    nome_responsavel, telefone_responsavel, cpf_responsavel, observacao_responsavel,
    cobranca_no_responsavel,
    onde_nos_conheceu, encaminhado_por, observacoes,
    last_attended_at, created_at, updated_at,
    risco_sinalizado_por, convenio_id, patient_scope
`;

// ─────────────────────────────────────────────────────────────────────────
// Patients core
// -----------------------------------------------------------------------------

/**
 * Lista pacientes do tenant ativo. Aceita filtros opcionais.
 * @param {object} opts - { tenantId, ownerId?, includeInactive?, limit? }
 */
export async function listPatients({ tenantId, ownerId = null, includeInactive = true, limit = null } = {}) {
    assertTenantId(tenantId);

    let q = supabase.from('patients').select(PATIENTS_SELECT_BASE).eq('tenant_id', tenantId);
    if (ownerId) q = q.eq('owner_id', ownerId);
    if (!includeInactive) q = q.neq('status', 'Inativo');
    if (limit) q = q.limit(limit);
    q = q.order('created_at', { ascending: false });

    const { data, error } = await q;
    if (error) throw error;
    return data || [];
}

export async function getPatientById(id, { tenantId } = {}) {
    if (!id) throw new Error('id obrigatório');
    assertTenantId(tenantId);
    const { data, error } = await supabase
        .from('patients')
        .select(PATIENTS_SELECT_BASE)
        .eq('id', id)
        .eq('tenant_id', tenantId)
        .maybeSingle();
    if (error) throw error;
    return data;
}

export async function createPatient(payload) {
    const tenantId = payload?.tenant_id;
    assertTenantId(tenantId);
    const ownerId = payload?.owner_id || (await getUid());
    const row = { ...payload, tenant_id: tenantId, owner_id: ownerId };
    const { data, error } = await supabase.from('patients').insert(row).select(PATIENTS_SELECT_BASE).single();
    if (error) throw error;
    return data;
}

export async function updatePatient(id, patch, { tenantId } = {}) {
    if (!id) throw new Error('id obrigatório');
    assertTenantId(tenantId);
    const { data, error } = await supabase
        .from('patients')
        .update(patch)
        .eq('id', id)
        .eq('tenant_id', tenantId)
        .select(PATIENTS_SELECT_BASE)
        .single();
    if (error) throw error;
    return data;
}

export async function softDeletePatient(id, { tenantId } = {}) {
    if (!id) throw new Error('id obrigatório');
    assertTenantId(tenantId);
    const { error } = await supabase
        .from('patients')
        .update({ status: 'Arquivado' })
        .eq('id', id)
        .eq('tenant_id', tenantId);
    if (error) throw error;
}

// Pra restaurar um paciente arquivado, use `reactivatePatient` do
// composable `usePatientLifecycle` — fonte única de verdade pra toda
// transição de status (Inativo/Arquivado/Alta/Encaminhado → Ativo).

// ─────────────────────────────────────────────────────────────────────────
// Groups
// -----------------------------------------------------------------------------
export async function listGroups({ tenantId, ownerId = null } = {}) {
    assertTenantId(tenantId);
    let q = supabase.from('patient_groups').select('id, nome, cor, is_system, owner_id, is_active').eq('tenant_id', tenantId).eq('is_active', true);
    if (ownerId) q = q.or(`is_system.eq.true,owner_id.eq.${ownerId}`);
    q = q.order('nome', { ascending: true });
    const { data, error } = await q;
    if (error) throw error;
    return (data || []).map((g) => ({ id: g.id, name: g.nome, color: g.cor, isSystem: g.is_system }));
}

export async function listGroupsByPatient(patientIds, { tenantId } = {}) {
    if (!patientIds?.length) return [];
    assertTenantId(tenantId);
    const { data, error } = await supabase
        .from('patient_group_patient')
        .select('patient_id, patient_group_id')
        .eq('tenant_id', tenantId)
        .in('patient_id', patientIds);
    if (error) throw error;
    return data || [];
}

// ─────────────────────────────────────────────────────────────────────────
// Tags
// -----------------------------------------------------------------------------
export async function listTags({ tenantId, ownerId = null } = {}) {
    assertTenantId(tenantId);
    let q = supabase.from('patient_tags').select('id, nome, cor, owner_id').eq('tenant_id', tenantId);
    if (ownerId) q = q.eq('owner_id', ownerId);
    const { data, error } = await q;
    if (error) throw error;
    return (data || []).map((t) => ({ id: t.id, name: t.nome, color: t.cor }));
}

export async function listTagsByPatient(patientIds, { tenantId } = {}) {
    if (!patientIds?.length) return [];
    assertTenantId(tenantId);
    const { data, error } = await supabase
        .from('patient_patient_tag')
        .select('patient_id, tag_id')
        .eq('tenant_id', tenantId)
        .in('patient_id', patientIds);
    if (error) throw error;
    return data || [];
}

/**
 * Retorna {groupIds, tagIds} de um paciente.
 */
export async function getPatientRelations(patientId) {
    if (!patientId) return { groupIds: [], tagIds: [] };
    const [{ data: g, error: ge }, { data: t, error: te }] = await Promise.all([
        supabase.from('patient_group_patient').select('patient_group_id').eq('patient_id', patientId),
        supabase.from('patient_patient_tag').select('tag_id').eq('patient_id', patientId)
    ]);
    if (ge) throw ge;
    if (te) throw te;
    return {
        groupIds: (g || []).map((x) => x.patient_group_id).filter(Boolean),
        tagIds: (t || []).map((x) => x.tag_id).filter(Boolean)
    };
}

/**
 * Substitui o grupo do paciente (1:1 — sistema atual).
 */
export async function replacePatientGroup(patientId, groupId, { tenantId } = {}) {
    if (!patientId) throw new Error('patientId obrigatório');
    const { error: del } = await supabase.from('patient_group_patient').delete().eq('patient_id', patientId);
    if (del) throw del;
    if (!groupId) return;
    const { error: ins } = await supabase
        .from('patient_group_patient')
        .insert({ patient_id: patientId, patient_group_id: groupId, tenant_id: tenantId });
    if (ins) throw ins;
}

/**
 * Substitui as tags do paciente (lista). Limpa antigas do owner + inserta as novas.
 */
export async function replacePatientTags(patientId, tagIds, { tenantId, ownerId } = {}) {
    if (!patientId) throw new Error('patientId obrigatório');
    if (!ownerId) throw new Error('ownerId obrigatório');
    const { error: del } = await supabase
        .from('patient_patient_tag')
        .delete()
        .eq('patient_id', patientId)
        .eq('owner_id', ownerId);
    if (del) throw del;

    const clean = Array.from(new Set((tagIds || []).filter(Boolean)));
    if (!clean.length) return;
    const { error: ins } = await supabase
        .from('patient_patient_tag')
        .insert(clean.map((tag_id) => ({ owner_id: ownerId, patient_id: patientId, tag_id, tenant_id: tenantId })));
    if (ins) throw ins;
}

// ─────────────────────────────────────────────────────────────────────────
// Sessões agregadas (V#8 — get_patient_session_counts RPC)
// -----------------------------------------------------------------------------
/**
 * Retorna contagem + última sessão por paciente. Usa RPC SECURITY DEFINER.
 * @param {string[]} patientIds
 * @returns {Array<{patient_id, session_count, last_session_at}>}
 */
export async function getSessionCounts(patientIds) {
    if (!patientIds?.length) return [];
    const { data, error } = await supabase.rpc('get_patient_session_counts', { p_patient_ids: patientIds });
    if (error) throw error;
    return data || [];
}
