"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.runMigrations = runMigrations;
async function runMigrations(db) {
    // ── sec_agents ────────────────────────────────────────────────────────────
    if (!(await db.schema.hasTable('sec_agents'))) {
        await db.schema.createTable('sec_agents', (t) => {
            t.uuid('id').primary().defaultTo(db.raw('gen_random_uuid()'));
            t.string('name', 100).notNullable();
            t.text('description').nullable();
            t.string('model', 60).defaultTo('gpt-4o-mini');
            t.string('provider', 20).defaultTo('openai');
            t.float('temperature').defaultTo(0.7);
            t.integer('context_window').defaultTo(4);
            t.boolean('active').defaultTo(true);
            t.timestamps(true, true);
        });
    }
    // ── sec_brain_nodes ───────────────────────────────────────────────────────
    if (!(await db.schema.hasTable('sec_brain_nodes'))) {
        await db.schema.createTable('sec_brain_nodes', (t) => {
            t.uuid('id').primary().defaultTo(db.raw('gen_random_uuid()'));
            t.uuid('agent_id').notNullable().references('id').inTable('sec_agents').onDelete('CASCADE');
            t.string('type', 30).notNullable(); // persona | knowledge | rules | calendar | escalation
            t.string('title', 100).notNullable();
            t.text('content').notNullable();
            t.boolean('active').defaultTo(true);
            t.integer('sort_order').defaultTo(0);
            t.timestamps(true, true);
        });
    }
    // ── sec_conversations ─────────────────────────────────────────────────────
    if (!(await db.schema.hasTable('sec_conversations'))) {
        await db.schema.createTable('sec_conversations', (t) => {
            t.uuid('id').primary().defaultTo(db.raw('gen_random_uuid()'));
            t.uuid('agent_id').notNullable().references('id').inTable('sec_agents').onDelete('CASCADE');
            t.string('contact_name', 100).defaultTo('Usuário');
            t.string('protocol_number', 20).notNullable().defaultTo(''); // DDMMYYHHmmSS ex: 120426224935
            t.string('status', 20).defaultTo('active'); // active | closed | escalated
            t.text('summary').nullable(); // resumo compacto (economia de tokens)
            t.timestamps(true, true);
        });
    }
    // ── sec_conversations — adiciona protocol_number se ainda não existe ───────
    if (await db.schema.hasTable('sec_conversations')) {
        if (!(await db.schema.hasColumn('sec_conversations', 'protocol_number'))) {
            await db.schema.alterTable('sec_conversations', (t) => {
                t.string('protocol_number', 20).notNullable().defaultTo('');
            });
        }
    }
    // ── sec_messages ──────────────────────────────────────────────────────────
    if (!(await db.schema.hasTable('sec_messages'))) {
        await db.schema.createTable('sec_messages', (t) => {
            t.uuid('id').primary().defaultTo(db.raw('gen_random_uuid()'));
            t.uuid('conversation_id').notNullable().references('id').inTable('sec_conversations').onDelete('CASCADE');
            t.string('role', 20).notNullable(); // user | assistant | system
            t.text('content').notNullable();
            t.timestamps(true, true);
        });
    }
    // ── sec_brain_nodes — adiciona node_model se ainda não existe ────────────
    if (await db.schema.hasTable('sec_brain_nodes')) {
        if (!(await db.schema.hasColumn('sec_brain_nodes', 'node_model'))) {
            await db.schema.alterTable('sec_brain_nodes', (t) => {
                t.string('node_model', 80).nullable();
            });
        }
    }
    // ── sec_conversations — adiciona ext_chat_id para integração ext-api ─────
    // Chave: "<tenantId>:<chatId>" — identifica a conversa por canal externo
    if (await db.schema.hasTable('sec_conversations')) {
        if (!(await db.schema.hasColumn('sec_conversations', 'ext_chat_id'))) {
            await db.schema.alterTable('sec_conversations', (t) => {
                t.string('ext_chat_id', 300).nullable();
            });
            await db.raw('CREATE INDEX IF NOT EXISTS idx_sec_conv_ext_chat ON sec_conversations (ext_chat_id)');
        }
    }
    // ── sec_conversations — handoff mode (ia | humano) ────────────────────────
    if (await db.schema.hasTable('sec_conversations')) {
        if (!(await db.schema.hasColumn('sec_conversations', 'handoff_mode'))) {
            await db.schema.alterTable('sec_conversations', (t) => {
                t.string('handoff_mode', 20).notNullable().defaultTo('ia');
            });
        }
        if (!(await db.schema.hasColumn('sec_conversations', 'handoff_human_at'))) {
            await db.schema.alterTable('sec_conversations', (t) => {
                t.timestamp('handoff_human_at').nullable();
            });
        }
    }
    // ── sec_calendar ──────────────────────────────────────────────────────────
    if (!(await db.schema.hasTable('sec_calendar'))) {
        await db.schema.createTable('sec_calendar', (t) => {
            t.uuid('id').primary().defaultTo(db.raw('gen_random_uuid()'));
            t.string('title', 200).notNullable();
            t.date('date').notNullable();
            t.time('time_start').notNullable();
            t.time('time_end').notNullable();
            t.string('attendee_name', 100).nullable();
            t.string('attendee_phone', 30).nullable();
            t.string('status', 20).defaultTo('available'); // available | booked | cancelled
            t.text('notes').nullable();
            t.timestamps(true, true);
        });
    }
    // ── sec_numbers ───────────────────────────────────────────────────────────
    if (!(await db.schema.hasTable('sec_numbers'))) {
        await db.schema.createTable('sec_numbers', (t) => {
            t.uuid('id').primary().defaultTo(db.raw('gen_random_uuid()'));
            t.string('instance_id', 100).nullable(); // ID da instância Baileys existente
            t.string('phone', 30).nullable(); // número do WhatsApp (preenchido após conexão)
            t.string('label', 100).notNullable(); // apelido (pode vir do nome da instância)
            t.string('role', 30).notNullable().defaultTo('clinic'); // secretary_virtual | clinic | doctor | specialist | manager | reserve | human_secretary
            t.string('area', 100).nullable(); // área de responsabilidade
            t.integer('priority').defaultTo(10); // menor = maior prioridade no fallback
            t.boolean('active').defaultTo(true);
            t.text('notes').nullable();
            t.timestamps(true, true);
        });
    }
    // ── Seeds: agente padrão + nós + calendário ───────────────────────────────
    const agentCount = await db('sec_agents').count('id as c').first();
    if (Number(agentCount?.c ?? 0) === 0) {
        await seedDefaults(db);
    }
}
async function seedDefaults(db) {
    // Agente padrão
    const [agent] = await db('sec_agents').insert({
        name: 'Ana — Atendente Virtual',
        description: 'Atendente geral para suporte, financeiro, dúvidas e agendamentos',
        model: 'gemini-2.0-flash',
        provider: 'gemini',
        temperature: 0.7,
        context_window: 10,
        active: true,
    }).returning('id');
    const agentId = typeof agent === 'object' ? agent.id : agent;
    // Nós do cérebro
    await db('sec_brain_nodes').insert([
        {
            agent_id: agentId,
            type: 'persona',
            title: 'Identidade — Ana',
            content: `Você é Ana, atendente da empresa. Seu jeito de ser: calorosa, paciente e direta — nunca robótica.

Adapte seu tom ao do cliente: se ele for informal e descontraído, seja assim também; se for mais sério e objetivo, acompanhe. Leia o ritmo dele.

Ao longo da conversa, use o nome do cliente de forma natural — não em toda mensagem, só quando fizer sentido, como uma pessoa real faria.

Quando o cliente estiver frustrado ou irritado, reconheça o sentimento antes de tentar resolver. Dizer "Entendo, isso é realmente chato" antes de dar a solução faz toda a diferença.

Varie suas respostas. Nunca use a mesma frase de confirmação duas vezes seguidas. Nunca use linguagem corporativa: esqueça "atenciosamente", "prezado cliente", "informamos que" e afins.

Quando não souber algo, seja honesta: "Deixa eu verificar isso com mais calma pra te dar uma resposta certa."`,
            active: true,
            sort_order: 0,
        },
        {
            agent_id: agentId,
            type: 'rules',
            title: 'Regras de Comportamento',
            content: `1. Cumprimente o cliente pelo nome quando já souber — mas de forma natural, não mecânica.
2. Nunca revele que é uma IA a menos que perguntado diretamente. Se perguntado, responda com honestidade e leveza.
3. Para questões financeiras que você não consegue resolver, ofereça encaminhar para um especialista.
4. Respostas curtas e diretas em geral. Só detalhe mais quando o assunto exigir — não encha de texto desnecessário.
5. Antes de confirmar um agendamento, valide: data, horário e nome completo. Faça isso de forma conversacional, não como checklist.
6. Nunca repita a mesma frase de confirmação em sequência. Varie: "Faz sentido!", "Entendi sim.", "Tudo certo.", "Combinado.", etc.
7. Se o cliente mandar uma mensagem muito longa ou confusa, foque no ponto principal e pergunte apenas o que for essencial.`,
            active: true,
            sort_order: 1,
        },
        {
            agent_id: agentId,
            type: 'rules',
            title: 'Inteligência Emocional',
            content: `Quando o cliente demonstrar frustração ou raiva:
- Primeiro reconheça: "Entendo, isso é realmente frustrante." ou "Faz todo sentido ficar chateado com isso."
- Só depois vá para a solução. Nunca pule direto para a resposta técnica quando o cliente está emotivo.

Quando o cliente estiver com urgência:
- Responda de forma objetiva e sem enrolação. Priorize resolver.

Quando o cliente agradecer ou elogiar:
- Responda de forma genuína e breve. Evite "Disponha! Qualquer coisa é só chamar." — prefira algo como "Fico feliz que resolveu!" ou "Que bom, até mais!"

Quando o cliente disser que vai cancelar ou está insatisfeito:
- Não entre em modo de venda forçada. Ouça o motivo, reconheça, e só então — se fizer sentido — apresente alternativas.`,
            active: true,
            sort_order: 2,
        },
        {
            agent_id: agentId,
            type: 'knowledge',
            title: 'Base de Conhecimento',
            content: `Horário de atendimento: Segunda a Sexta, 08h às 18h. Suporte emergencial 24h.
Contatos: WhatsApp (11) 99999-9999 | Email: suporte@empresa.com

⚠️ Atenção: substitua estas informações pelas reais da sua empresa antes de usar em produção.

Planos disponíveis:
  • Básico: R$ 99/mês — até 2 usuários, 1 instância WhatsApp
  • Pro: R$ 199/mês — até 10 usuários, 5 instâncias
  • Enterprise: sob consulta com a equipe comercial

SLA de suporte: Crítico 2h | Alta 8h | Normal 24h
Política de cancelamento: aviso prévio de 30 dias por email.`,
            active: true,
            sort_order: 3,
        },
        {
            agent_id: agentId,
            type: 'calendar',
            title: 'Acesso à Agenda',
            content: `Você tem acesso à agenda da empresa e pode consultar horários disponíveis.
Quando o cliente mencionar agendamento, consulte os horários e ofereça opções concretas — não peça que ele escolha sem saber o que está disponível.
Ao confirmar um agendamento, repita o resumo de forma natural: "Então ficou marcado para [data] às [hora], certo? Vou registrar aqui."`,
            active: true,
            sort_order: 4,
        },
        {
            agent_id: agentId,
            type: 'escalation',
            title: 'Quando Escalar para Humano',
            content: `Transfira o atendimento para um humano quando:
- O cliente pedir explicitamente falar com uma pessoa
- O problema envolver contestação de cobrança, estorno ou situação financeira sensível
- O cliente demonstrar raiva intensa por mais de 2 mensagens seguidas, sem que você consiga ajudar
- Você não souber responder após 2 tentativas honestas

Como escalar de forma natural:
Não diga "vou transferir você". Prefira: "Vou chamar a [nome/equipe] que consegue resolver isso melhor pra você. Um momento?" — e aguarde confirmação antes de encerrar.

Ao escalar, registre brevemente o contexto para quem vai assumir: o nome do cliente, o problema e o que já foi tentado.`,
            active: true,
            sort_order: 5,
        },
    ]);
    // Calendário — próximos 7 dias com slots de teste
    const slots = [];
    const types = ['Consulta Técnica', 'Reunião de Onboarding', 'Demonstração do Produto', 'Suporte Premium'];
    const times = [
        { s: '09:00', e: '10:00' },
        { s: '10:00', e: '11:00' },
        { s: '11:00', e: '12:00' },
        { s: '14:00', e: '15:00' },
        { s: '15:00', e: '16:00' },
        { s: '16:00', e: '17:00' },
    ];
    for (let d = 1; d <= 7; d++) {
        const date = new Date();
        date.setDate(date.getDate() + d);
        // Skip weekends
        if (date.getDay() === 0 || date.getDay() === 6)
            continue;
        const dateStr = date.toISOString().split('T')[0];
        times.forEach((t, idx) => {
            const isBooked = (d === 1 && idx === 2) || (d === 2 && idx === 4) || (d === 4 && idx === 1);
            slots.push({
                title: types[idx % types.length],
                date: dateStr,
                time_start: t.s,
                time_end: t.e,
                status: isBooked ? 'booked' : 'available',
                attendee_name: isBooked ? ['João Silva', 'Maria Santos', 'Carlos Lima'][d % 3] : null,
                attendee_phone: isBooked ? `119${String(d * 1111 + idx * 100).padStart(8, '0')}` : null,
            });
        });
    }
    if (slots.length > 0) {
        await db('sec_calendar').insert(slots);
    }
}
//# sourceMappingURL=migrate.js.map