/*
|--------------------------------------------------------------------------
| Agência PSI
|--------------------------------------------------------------------------
| Criado e desenvolvido por Leonardo Nohama
|
| Tecnologia aplicada à escuta.
| Estrutura para o cuidado.
|
| Arquivo: src/services/GruposPacientes.service.js
| Data: 2026
| Local: São Carlos/SP — Brasil
|--------------------------------------------------------------------------
| © 2026 — Todos os direitos reservados
|--------------------------------------------------------------------------
*/
import { supabase } from '@/lib/supabase/client';

import { tenantDb } from '@/lib/supabase/tenantClient';
function pickCount(row) {
    return row?.patients_count ?? row?.patient_count ?? 0;
}

async function getOwnerId() {
    const { data, error } = await supabase.auth.getUser();
    if (error) throw error;
    const uid = data?.user?.id;
    if (!uid) throw new Error('Sessão inválida.');
    return uid;
}

async function getActiveTenantId(uid) {
    const { data, error } = await supabase.from('tenant_members').select('tenant_id').eq('user_id', uid).eq('status', 'active').order('created_at', { ascending: false }).limit(1).single();
    if (error) throw error;
    if (!data?.tenant_id) throw new Error('Tenant não encontrado.');
    return data.tenant_id;
}

function normalizeNome(s) {
    return String(s || '')
        .trim()
        .toLowerCase()
        .replace(/\s+/g, ' ');
}

function isUniqueViolation(err) {
    if (!err) return false;
    if (err.code === '23505') return true;
    const msg = String(err.message || '');
    return /duplicate key value violates unique constraint/i.test(msg);
}

/**
 * Lista grupos do usuário + grupos do sistema, já com contagem.
 * Usa a view v_patient_groups_with_counts (preferencial).
 * Fallback: tabela patient_groups + contagem pela pivot.
 */
export async function listGroupsWithCounts() {
    const ownerId = await getOwnerId();

    // 1) View (preferencial) — agora já é a fonte correta
    const { data: vData, error: vErr } = await tenantDb().from('v_patient_groups_with_counts').select('*').or(`owner_id.eq.${ownerId},is_system.eq.true`).order('nome', { ascending: true });

    if (!vErr) {
        return (vData || []).map((r) => ({
            ...r,
            patients_count: pickCount(r)
        }));
    }

    // 2) Fallback (caso view não exista / erro de schema)
    const { data: groups, error: gErr } = await tenantDb().from('patient_groups').select('id,nome,cor,is_system,is_active,owner_id,created_at,updated_at').or(`owner_id.eq.${ownerId},is_system.eq.true`).order('nome', { ascending: true });
    if (gErr) throw gErr;

    const ids = (groups || []).map((g) => g.id).filter(Boolean);
    if (!ids.length) return [];

    // conta pacientes por grupo na pivot
    const { data: rel, error: rErr } = await tenantDb().from('patient_group_patient').select('patient_group_id').in('patient_group_id', ids);
    if (rErr) throw rErr;

    const counts = new Map();
    for (const row of rel || []) {
        const gid = row.patient_group_id;
        if (!gid) continue;
        counts.set(gid, (counts.get(gid) || 0) + 1);
    }

    return (groups || []).map((g) => ({
        ...g,
        patients_count: counts.get(g.id) || 0
    }));
}

export async function createGroup(nome, cor = null) {
    const ownerId = await getOwnerId();
    const tenantId = await getActiveTenantId(ownerId);

    const raw = String(nome || '').trim();
    if (!raw) throw new Error('Nome do grupo é obrigatório.');

    const nNorm = normalizeNome(raw);

    // proteção extra no front: busca por igualdade "normalizada"
    // (mantém RLS como autoridade final, mas evita UX ruim)
    const { data: existing, error: exErr } = await tenantDb().from('patient_groups').select('id,nome').eq('owner_id', ownerId).eq('is_system', false).limit(50);

    if (!exErr && (existing || []).some((r) => normalizeNome(r.nome) === nNorm)) {
        throw new Error('Já existe um grupo com esse nome.');
    }

    const payload = {
        owner_id: ownerId,
        nome: raw,
        cor: cor || null
    };

    const { data, error } = await tenantDb().from('patient_groups').insert(payload).select('id,nome,cor,is_system,owner_id,is_active,created_at,updated_at').single();

    if (error) {
        if (isUniqueViolation(error)) throw new Error('Já existe um grupo com esse nome.');
        throw error;
    }

    return data;
}

export async function updateGroup(id, nome, cor = null) {
    const ownerId = await getOwnerId();

    const raw = String(nome || '').trim();
    if (!id) throw new Error('ID inválido.');
    if (!raw) throw new Error('Nome do grupo é obrigatório.');

    // (opcional) valida duplicidade entre os grupos do owner (não-system)
    const nNorm = normalizeNome(raw);
    const { data: existing, error: exErr } = await tenantDb().from('patient_groups').select('id,nome').eq('owner_id', ownerId).eq('is_system', false).neq('id', id).limit(80);

    if (!exErr && (existing || []).some((r) => normalizeNome(r.nome) === nNorm)) {
        throw new Error('Já existe um grupo com esse nome.');
    }

    const { data, error } = await tenantDb().from('patient_groups')
        .update({ nome: raw, cor: cor || null, updated_at: new Date().toISOString() })
        .eq('id', id)
        .eq('owner_id', ownerId)
        .eq('is_system', false)
        .select('id,nome,cor,is_system,owner_id,is_active,created_at,updated_at')
        .single();

    if (error) {
        if (isUniqueViolation(error)) throw new Error('Já existe um grupo com esse nome.');
        throw error;
    }

    return data;
}

export async function deleteGroup(id) {
    const ownerId = await getOwnerId();

    if (!id) throw new Error('ID inválido.');

    const { error } = await tenantDb().from('patient_groups').delete().eq('id', id).eq('owner_id', ownerId).eq('is_system', false);

    if (error) throw error;
    return true;
}
