/**
 * usePatientSupportContacts.spec.js — V#9
 *
 * Cobre add/remove/reset/load/save/iniciaisFor + sanitização do save.
 */
import { describe, it, expect, vi, beforeEach } from 'vitest';

// Builder thenable: cada chamada (.select/.eq/.order/.delete/.insert) retorna um
// objeto thenable. Pra testes, configuramos o resultado final via setNext(value).
let nextResult = { data: [], error: null };
let lastInsertArg = null;
let deleteCalled = false;

function makeChain() {
    const chain = {};
    const passthrough = (..._a) => chain;
    chain.select = passthrough;
    chain.eq = passthrough;
    chain.order = passthrough;
    chain.delete = (...a) => { deleteCalled = true; return chain; };
    chain.insert = (rows) => { lastInsertArg = rows; return chain; };
    chain.then = (onFulfilled, onRejected) => Promise.resolve(nextResult).then(onFulfilled, onRejected);
    return chain;
}

const fromMock = vi.fn(() => makeChain());

vi.mock('@/lib/supabase/client', () => ({
    supabase: { from: (...a) => fromMock(...a) }
}));

const { usePatientSupportContacts } = await import('../usePatientSupportContacts.js');

beforeEach(() => {
    fromMock.mockClear();
    nextResult = { data: [], error: null };
    lastInsertArg = null;
    deleteCalled = false;
});

describe('add / remove / reset', () => {
    it('add cria contato com defaults e _k único', () => {
        const c = usePatientSupportContacts();
        expect(c.contatos.value).toEqual([]);
        c.add();
        c.add();
        expect(c.contatos.value).toHaveLength(2);
        expect(c.contatos.value[0]._k).not.toBe(c.contatos.value[1]._k);
        expect(c.contatos.value[0]).toMatchObject({ nome: '', telefone: '', is_primario: false });
    });

    it('remove pelo índice', () => {
        const c = usePatientSupportContacts();
        c.add(); c.add(); c.add();
        const middleK = c.contatos.value[1]._k;
        c.remove(1);
        expect(c.contatos.value).toHaveLength(2);
        expect(c.contatos.value.find((x) => x._k === middleK)).toBeUndefined();
    });

    it('reset esvazia', () => {
        const c = usePatientSupportContacts();
        c.add(); c.add();
        c.reset();
        expect(c.contatos.value).toEqual([]);
    });
});

describe('iniciaisFor', () => {
    it('extrai 2 primeiras iniciais maiúsculas', () => {
        const { iniciaisFor } = usePatientSupportContacts();
        expect(iniciaisFor('joão pedro silva')).toBe('JP');
        expect(iniciaisFor('Maria')).toBe('M');
        expect(iniciaisFor('')).toBe('');
        expect(iniciaisFor(null)).toBe('');
        expect(iniciaisFor('A B C D')).toBe('AB');
    });
});

describe('load — popula contatos do paciente', () => {
    it('sem patientId, esvazia', async () => {
        const c = usePatientSupportContacts();
        c.add();
        await c.load(null);
        expect(c.contatos.value).toEqual([]);
        expect(fromMock).not.toHaveBeenCalled();
    });

    it('mapeia rows do banco para shape do composable (com fmtPhone)', async () => {
        nextResult = {
            data: [
                { id: 'a', nome: 'Maria', relacao: 'mãe', tipo: 'familiar', telefone: '11987654321', email: 'maria@x.com', is_primario: true },
                { id: 'b', nome: 'Bia', relacao: 'amiga', tipo: null, telefone: null, email: null, is_primario: false }
            ],
            error: null
        };

        const c = usePatientSupportContacts();
        await c.load('p-1');

        expect(fromMock).toHaveBeenCalledWith('patient_support_contacts');
        expect(c.contatos.value).toHaveLength(2);
        expect(c.contatos.value[0]).toMatchObject({
            _k: 'a', nome: 'Maria', is_primario: true, telefone: '(11) 98765-4321'
        });
        expect(c.contatos.value[1]).toMatchObject({ _k: 'b', telefone: '', is_primario: false });
    });

    it('em erro, esvazia silenciosamente', async () => {
        nextResult = { data: null, error: new Error('rls') };
        const c = usePatientSupportContacts();
        c.add();
        await c.load('p-1');
        expect(c.contatos.value).toEqual([]);
    });
});

describe('save — sanitização e regras', () => {
    it('exige patientId', async () => {
        const c = usePatientSupportContacts();
        await expect(c.save(null, 't', 'o')).rejects.toThrow(/patientId/);
    });

    it('descarta contatos com nome vazio', async () => {
        nextResult = { error: null };

        const c = usePatientSupportContacts();
        c.add(); c.add();
        c.contatos.value[0].nome = 'Maria';
        c.contatos.value[0].telefone = '(11) 98765-4321';
        // contato 2 fica com nome vazio → descartado

        await c.save('p-1', 't-1', 'o-1');

        expect(deleteCalled).toBe(true);
        expect(lastInsertArg).toHaveLength(1);
        expect(lastInsertArg[0]).toMatchObject({
            patient_id: 'p-1', tenant_id: 't-1', owner_id: 'o-1',
            nome: 'Maria', telefone: '11987654321'
        });
    });

    it('se todos contatos têm nome vazio, não chama insert (só delete)', async () => {
        nextResult = { error: null };
        const c = usePatientSupportContacts();
        c.add();
        await c.save('p-1', 't-1', 'o-1');

        expect(deleteCalled).toBe(true);
        expect(lastInsertArg).toBe(null);
    });
});
