/*
 * useMelissaPacientesAside — paginação async DEDICADA pra coluna direita
 * da MelissaAgenda (lista de "Pacientes" lá no aside).
 * --------------------------------------------------
 * Por que existe (em vez de reaproveitar `useMelissaPacientes`):
 *   - useMelissaPacientes carrega TUDO num array só (até 1000) porque outras
 *     partes do sistema dependem da lista completa em memória (lookup por ID
 *     em eventos da agenda, página MelissaPacientes, cards de resumo).
 *   - A coluna do aside só precisa renderizar 6 por vez. Pra clínicas com
 *     milhares de pacientes, faz sentido essa coluna ir ao banco a cada
 *     página/busca em vez de paginar client-side em cima de um array gigante.
 *
 * Compromisso: a ordenação é alfabética (server-side por nome_completo). O
 * destaque visual de "novo paciente" continua funcionando (compara created_at
 * < 7 dias no consumer), mas pacientes novos NÃO são mais empurrados pro
 * topo da lista — eles aparecem na ordem alfabética normal. Pra ver os mais
 * recentes, usuário precisa filtrar/buscar pelo nome.
 *
 * Sanitização (regra do projeto):
 *   - busca trimada e capada em 100 chars
 *   - wildcards LIKE (%, _) são escapados antes de irem pro .ilike()
 *
 * Race-safety:
 *   - sequence number (_seq) ignora respostas tardias de queries antigas
 *     quando o usuário troca de página/digita rápido.
 */
import { ref, computed, watch } from 'vue';
import { supabase } from '@/lib/supabase/client';
import { tenantDb } from '@/lib/supabase/tenantClient';
import { useTenantStore } from '@/stores/tenantStore';

const SEARCH_MAX_LEN = 100;
const DEBOUNCE_MS = 250;

function normalizeStatus(s) {
    const v = String(s || '').toLowerCase().trim();
    if (!v) return 'Ativo';
    if (v === 'active' || v === 'ativo') return 'Ativo';
    if (v === 'inactive' || v === 'inativo') return 'Inativo';
    return v.charAt(0).toUpperCase() + v.slice(1);
}

// Escapa wildcards do LIKE/ILIKE pra evitar que o usuário injete
// padrões de busca não intencionais ao digitar % ou _.
function escapeLike(s) {
    return String(s).replace(/\\/g, '\\\\').replace(/%/g, '\\%').replace(/_/g, '\\_');
}

/**
 * @param {object} opts
 * @param {import('vue').Ref<number>} opts.pagina        ref 1-based
 * @param {import('vue').Ref<string>} opts.busca         ref de string (texto livre)
 * @param {number}                    [opts.porPagina=6] tamanho da página
 */
export function useMelissaPacientesAside(opts) {
    const { pagina, busca, porPagina = 6 } = opts;

    const tenantStore = useTenantStore();

    const pacientes = ref([]);
    const total = ref(0);
    const loading = ref(false);
    const error = ref(null);
    const _uid = ref(null);
    const _seq = ref(0);
    let _debounceTimer = null;

    async function _ensureUid() {
        if (_uid.value) return _uid.value;
        // Fast path: session já hidratada no storage (<10ms).
        const { data: ses } = await supabase.auth.getSession();
        const uid = ses?.session?.user?.id;
        if (uid) {
            _uid.value = uid;
            return uid;
        }
        // Fallback: round-trip pro auth server (cold start).
        const { data, error: err } = await supabase.auth.getUser();
        if (err) return null;
        _uid.value = data?.user?.id || null;
        return _uid.value;
    }

    async function _fetch() {
        const seq = ++_seq.value;
        const userId = await _ensureUid();
        if (typeof tenantStore.ensureLoaded === 'function') {
            await tenantStore.ensureLoaded();
        }
        const tid = tenantStore.activeTenantId || tenantStore.tenantId || null;

        if (!userId || !tid) {
            if (seq !== _seq.value) return;
            pacientes.value = [];
            total.value = 0;
            return;
        }

        // Sanitização da busca: trim + cap + escape de wildcards LIKE.
        const rawQ = String(busca.value || '').trim().slice(0, SEARCH_MAX_LEN);
        const hasQ = rawQ.length > 0;

        const start = Math.max(0, (pagina.value - 1) * porPagina);
        const end = start + porPagina - 1;

        loading.value = true;
        error.value = null;

        try {
            let q = tenantDb().from('patients')
                .select(
                    'id, nome_completo, email_principal, telefone, status, avatar_url, last_attended_at, created_at, data_nascimento',
                    { count: 'exact' }
                )
                .eq('owner_id', userId)
                
                // Mesmo critério do useMelissaPacientes original (onlyActive=true).
                // DB tem valores variados ('ativo'/'Ativo'/'active'); aceita os 3.
                .in('status', ['ativo', 'Ativo', 'active'])
                .order('nome_completo', { ascending: true })
                .range(start, end);

            if (hasQ) {
                q = q.ilike('nome_completo', `%${escapeLike(rawQ)}%`);
            }

            const { data, error: err, count } = await q;
            if (err) throw err;

            // Race-guard: outra chamada disparou enquanto esperávamos a resposta.
            if (seq !== _seq.value) return;

            pacientes.value = (data || []).map((r) => ({
                id: r.id,
                nome: r.nome_completo || '',
                email: r.email_principal || '',
                telefone: r.telefone || '',
                avatar_url: r.avatar_url || null,
                status: normalizeStatus(r.status),
                last_attended_at: r.last_attended_at || null,
                created_at: r.created_at || null,
                data_nascimento: r.data_nascimento || null
            }));
            total.value = count ?? 0;
        } catch (e) {
            if (seq !== _seq.value) return;
            error.value = e?.message || 'Erro ao carregar pacientes';
            pacientes.value = [];
            total.value = 0;
            // eslint-disable-next-line no-console
            console.warn('[useMelissaPacientesAside]', e);
        } finally {
            if (seq === _seq.value) loading.value = false;
        }
    }

    function _scheduleFetch({ debounce }) {
        if (_debounceTimer) {
            clearTimeout(_debounceTimer);
            _debounceTimer = null;
        }
        if (debounce) {
            _debounceTimer = setTimeout(() => {
                _debounceTimer = null;
                _fetch();
            }, DEBOUNCE_MS);
        } else {
            _fetch();
        }
    }

    // Página muda → fetch imediato (clique no paginator é deliberado).
    watch(pagina, () => _scheduleFetch({ debounce: false }), { immediate: true });
    // Busca muda → debounce (usuário digitando).
    watch(busca, () => {
        // Reset implícito: ao buscar, qualquer página > 1 deve voltar pra 1.
        // Como `pagina` é refs do consumer, não mexemos aqui — o consumer faz isso.
        _scheduleFetch({ debounce: true });
    });

    const totalPaginas = computed(() => Math.max(1, Math.ceil(total.value / porPagina)));

    return {
        pacientes,
        total,
        totalPaginas,
        loading,
        error,
        refetch: () => _scheduleFetch({ debounce: false })
    };
}
