/**
 * conversationDrawerStore.spec.js
 *
 * Cobre `classifySendError` — a logica que transforma a resposta de erro
 * do edge function send-whatsapp-message em um banner persistente
 * { code, status, message, hint, action, secondaryAction? }.
 *
 * O classify e' deterministico (puro, sem deps) entao o teste so valida
 * o mapeamento codigo+status -> banner. Cobre todos os ramos do switch
 * + o fallback generico.
 */
import { describe, it, expect } from 'vitest';
import { classifySendError } from '@/stores/conversationDrawerStore';

describe('classifySendError', () => {
    describe('5xx (servidor downstream fora)', () => {
        it.each([502, 503, 504])('http %i -> banner "fora do ar" + 2 CTAs', (status) => {
            const r = classifySendError('whatever', null, status);
            expect(r.status).toBe(status);
            expect(r.message).toMatch(/fora do ar/i);
            expect(r.action).toEqual({ label: 'Configurar WhatsApp', url: '/configuracoes/whatsapp' });
            expect(r.secondaryAction).toEqual({ label: 'Comprar créditos', url: '/configuracoes/creditos-whatsapp' });
        });

        it('http 502 sem code retornado ainda eh classificado', () => {
            const r = classifySendError(null, null, 502);
            expect(r.code).toBe('http_502');
            expect(r.message).toMatch(/fora do ar/i);
        });

        it('http 500 NAO cai no ramo 5xx (so 502/503/504)', () => {
            // 500 e' o catch geral do edge function, nao o "downstream fora"
            const r = classifySendError('TypeError: fetch failed', null, 500);
            expect(r.message).not.toMatch(/fora do ar/i);
        });
    });

    describe('insufficient_credits', () => {
        it('mostra CTA "Comprar creditos" sem secondary', () => {
            const r = classifySendError('insufficient_credits', null, 200);
            expect(r.message).toMatch(/saldo de créditos insuficiente/i);
            expect(r.action).toEqual({ label: 'Comprar créditos', url: '/configuracoes/creditos-whatsapp' });
            expect(r.secondaryAction).toBeUndefined();
        });
    });

    describe('canal nao configurado / inativo', () => {
        it.each([
            'canal whatsapp nao configurado',
            'canal whatsapp inativo',
            'erro: canal whatsapp nao configurado pra esse tenant'
        ])('codigo %s -> CTA Configurar agora', (code) => {
            const r = classifySendError(code, null, 400);
            expect(r.message).toMatch(/nenhum canal whatsapp ativo/i);
            expect(r.action).toEqual({ label: 'Configurar agora', url: '/configuracoes/whatsapp' });
        });
    });

    describe('credenciais incompletas', () => {
        it('evolution -> CTA Configuracoes WhatsApp', () => {
            const r = classifySendError('Credenciais Evolution incompletas', null, 400);
            expect(r.message).toMatch(/credenciais incompletas/i);
            expect(r.action.url).toBe('/configuracoes/whatsapp');
        });

        it('twilio -> sem CTA (suporte resolve)', () => {
            const r = classifySendError('Twilio credenciais incompletas', null, 400);
            expect(r.message).toMatch(/credenciais incompletas/i);
            expect(r.action).toBeNull();
            expect(r.hint).toMatch(/suporte/i);
        });
    });

    describe('falhas de provedor', () => {
        it('"evolution retornou 500" -> CTA Ver status', () => {
            const r = classifySendError('Evolution retornou 500', null, 502);
            // 502 entra no ramo 5xx primeiro (mais especifico) — comportamento ok
            expect(r.message).toMatch(/fora do ar/i);
        });

        it('"evolution retornou 500" sem status 5xx -> CTA Ver status', () => {
            const r = classifySendError('Evolution retornou 500', null, 200);
            expect(r.message).toMatch(/whatsapp pessoal não respondeu/i);
            expect(r.action).toEqual({ label: 'Ver status', url: '/configuracoes/whatsapp' });
        });

        it('twilio_send_failed_xxx -> CTA Configuracoes WhatsApp', () => {
            const r = classifySendError('twilio_send_failed_21610', null, 400);
            expect(r.message).toMatch(/whatsapp oficial recusou/i);
            expect(r.action.url).toBe('/configuracoes/whatsapp');
        });
    });

    describe('auth/permissao', () => {
        it('auth -> sessao expirou, sem CTA', () => {
            const r = classifySendError('auth', null, 401);
            expect(r.message).toMatch(/sessão expirou/i);
            expect(r.action).toBeNull();
        });

        it('forbidden -> sem permissao, sem CTA', () => {
            const r = classifySendError('forbidden', null, 403);
            expect(r.message).toMatch(/permissão/i);
            expect(r.action).toBeNull();
        });
    });

    describe('edge function generic 4xx/5xx wrapper', () => {
        it('"Edge Function returned a non-2xx status code" -> CTA Configurar', () => {
            const r = classifySendError('Edge Function returned a non-2xx status code', null, 400);
            expect(r.message).toMatch(/recusou o envio/i);
            expect(r.action.url).toBe('/configuracoes/whatsapp');
        });
    });

    describe('fallback generico', () => {
        it('codigo desconhecido com message preservada', () => {
            const r = classifySendError('weird_code_42', 'Algo deu errado especifico', 400);
            expect(r.code).toBe('weird_code_42');
            expect(r.message).toBe('Algo deu errado especifico'); // usa providedMessage
            expect(r.action.url).toBe('/configuracoes/whatsapp');
        });

        it('codigo vazio + message vazia -> mensagem padrao', () => {
            const r = classifySendError(null, null, null);
            expect(r.code).toBe('unknown');
            expect(r.message).toMatch(/não foi possível enviar/i);
            expect(r.hint).toBeTruthy();
        });
    });

    describe('robustez', () => {
        it('case-insensitive no codigo (DB pode ter case variavel)', () => {
            const r = classifySendError('INSUFFICIENT_CREDITS', null, 200);
            expect(r.message).toMatch(/saldo de créditos/i);
        });

        it('status nao-numerico vira null em vez de NaN', () => {
            const r = classifySendError('insufficient_credits', null, 'not a number');
            expect(r.status).toBeNull();
        });

        it('codigo nao-string nao quebra (defensivo)', () => {
            expect(() => classifySendError(undefined, null, null)).not.toThrow();
            expect(() => classifySendError(123, null, null)).not.toThrow();
            expect(() => classifySendError({}, null, null)).not.toThrow();
        });
    });
});
