import fs from 'fs';
import path from 'path';
import * as readline from 'readline';
import yaml from 'js-yaml';
// Walk squadsDir recursively, return all squad summaries
function discoverAllSquads(squadsDir) {
    const result = [];
    function walk(dir) {
        let entries;
        try {
            entries = fs.readdirSync(dir, { withFileTypes: true });
        }
        catch {
            return;
        }
        for (const entry of entries) {
            if (!entry.isDirectory())
                continue;
            if (entry.name.startsWith('.') || entry.name.startsWith('_'))
                continue;
            const fullPath = path.join(dir, entry.name);
            const yamlPath = path.join(fullPath, 'squad.yaml');
            if (fs.existsSync(yamlPath)) {
                try {
                    const raw = fs.readFileSync(yamlPath, 'utf-8');
                    const parsed = yaml.load(raw);
                    const s = parsed?.squad;
                    if (s) {
                        result.push({
                            code: s.code ?? entry.name,
                            name: s.name ?? entry.name,
                            description: s.description ?? '',
                            setor: s.setor,
                            grupo: s.grupo,
                            sessao: s.sessao,
                            dir: fullPath,
                        });
                    }
                }
                catch {
                    // Skip malformed YAML
                }
                // Don't recurse into squad directories
            }
            else {
                walk(fullPath);
            }
        }
    }
    walk(squadsDir);
    return result;
}
function buildClassificationPrompt(squads) {
    const list = squads
        .map((s) => `- code: ${s.code}, name: "${s.name}", description: "${s.description}"`)
        .join('\n');
    return `Você é um classificador de squads de IA para uma software house.
Para cada squad abaixo, identifique o Setor, Grupo e Sessão mais adequados.

Setores comuns: marketing, comercial, desenvolvimento, suporte, financeiro, rh, operacoes, estrategia, design, juridico, administrativo

Retorne APENAS um JSON válido (sem markdown, sem explicações), no seguinte formato:
[{"code":"<squad-code>","setor":"<setor>","grupo":"<grupo>","sessao":"<sessao>","confidence":"high"}]

Use "confidence":"low" quando não tiver certeza.
Use hifens em vez de espaços (ex: "redes-sociais").

Squads:
${list}`;
}
// Call Anthropic API directly — fast, no interactive session needed
async function inferBatchWithApi(squads) {
    const { default: Anthropic } = await import('@anthropic-ai/sdk');
    const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
    const response = await client.messages.create({
        model: 'claude-haiku-4-5-20251001',
        max_tokens: 2048,
        messages: [{ role: 'user', content: buildClassificationPrompt(squads) }],
    });
    const text = response.content
        .map((b) => (b.type === 'text' ? b.text : ''))
        .join('');
    const jsonMatch = text.match(/\[[\s\S]*\]/);
    if (!jsonMatch)
        throw new Error('No JSON array in API response');
    return JSON.parse(jsonMatch[0]);
}
// Heuristic fallback — keyword-based, no AI required
function inferHeuristic(squad) {
    const text = `${squad.code} ${squad.name} ${squad.description}`.toLowerCase();
    const RULES = [
        { setor: 'marketing', grupo: 'redes-sociais', sessao: 'instagram', keywords: ['instagram', 'reels', 'stories'] },
        { setor: 'marketing', grupo: 'redes-sociais', sessao: 'linkedin', keywords: ['linkedin'] },
        { setor: 'marketing', grupo: 'redes-sociais', sessao: 'twitter', keywords: ['twitter', 'x.com', 'tweet'] },
        { setor: 'marketing', grupo: 'conteudo', sessao: 'blog', keywords: ['blog', 'artigo', 'post'] },
        { setor: 'marketing', grupo: 'email', sessao: 'campanhas', keywords: ['email', 'newsletter', 'campanha'] },
        { setor: 'marketing', grupo: 'ads', sessao: 'google', keywords: ['google ads', 'adwords', 'sem'] },
        { setor: 'marketing', grupo: 'ads', sessao: 'meta', keywords: ['meta ads', 'facebook ads'] },
        { setor: 'comercial', grupo: 'vendas', sessao: 'prospecao', keywords: ['sdr', 'prospeccao', 'leads', 'prospect'] },
        { setor: 'comercial', grupo: 'vendas', sessao: 'proposta', keywords: ['proposta', 'cotacao', 'orcamento'] },
        { setor: 'comercial', grupo: 'crm', sessao: 'gestao', keywords: ['crm', 'pipeline', 'funil'] },
        { setor: 'desenvolvimento', grupo: 'produto', sessao: 'frontend', keywords: ['frontend', 'react', 'vue', 'angular', 'ui'] },
        { setor: 'desenvolvimento', grupo: 'produto', sessao: 'backend', keywords: ['backend', 'api', 'server', 'banco de dados'] },
        { setor: 'desenvolvimento', grupo: 'produto', sessao: 'devops', keywords: ['devops', 'ci/cd', 'deploy', 'docker', 'kubernetes'] },
        { setor: 'desenvolvimento', grupo: 'qualidade', sessao: 'qa', keywords: ['qa', 'teste', 'qualidade', 'bug'] },
        { setor: 'suporte', grupo: 'atendimento', sessao: 'l1', keywords: ['suporte', 'atendimento', 'helpdesk', 'l1', 'l2'] },
        { setor: 'rh', grupo: 'recrutamento', sessao: 'selecao', keywords: ['recrutamento', 'selecao', 'entrevista', 'vaga'] },
        { setor: 'rh', grupo: 'pessoas', sessao: 'cultura', keywords: ['cultura', 'onboarding', 'treinamento', 'clima'] },
        { setor: 'financeiro', grupo: 'contabilidade', sessao: 'fiscal', keywords: ['financeiro', 'contabil', 'fiscal', 'nfe', 'fatura'] },
        { setor: 'juridico', grupo: 'contratos', sessao: 'analise', keywords: ['juridico', 'contrato', 'legal', 'compliance'] },
        { setor: 'design', grupo: 'visual', sessao: 'identidade', keywords: ['design', 'branding', 'identidade', 'logo', 'marca'] },
        { setor: 'estrategia', grupo: 'planejamento', sessao: 'okr', keywords: ['estrategia', 'okr', 'planejamento', 'kpi', 'meta'] },
        { setor: 'operacoes', grupo: 'processos', sessao: 'gestao', keywords: ['operacoes', 'processo', 'workflow', 'automacao'] },
    ];
    for (const rule of RULES) {
        if (rule.keywords.some((kw) => text.includes(kw))) {
            return { code: squad.code, setor: rule.setor, grupo: rule.grupo, sessao: rule.sessao, confidence: 'low' };
        }
    }
    return { code: squad.code, setor: 'geral', grupo: 'squads', sessao: 'default', confidence: 'low' };
}
// Classify all squads: try Anthropic API in batches, fall back to heuristic
async function inferHierarchyWithClaude(squads) {
    const hasApiKey = !!process.env.ANTHROPIC_API_KEY;
    if (!hasApiKey) {
        console.log('  ANTHROPIC_API_KEY não definida — usando classificação heurística.\n');
        return squads.map(inferHeuristic);
    }
    const BATCH_SIZE = 10;
    const results = [];
    const batches = Math.ceil(squads.length / BATCH_SIZE);
    for (let i = 0; i < squads.length; i += BATCH_SIZE) {
        const batch = squads.slice(i, i + BATCH_SIZE);
        const batchNum = Math.floor(i / BATCH_SIZE) + 1;
        process.stdout.write(`  Classificando batch ${batchNum}/${batches} (${batch.length} squads)...`);
        try {
            const batchResults = await inferBatchWithApi(batch);
            results.push(...batchResults);
            process.stdout.write(' ✓\n');
        }
        catch (err) {
            process.stdout.write(` falhou (${err.message}) — usando heurística para este batch.\n`);
            results.push(...batch.map(inferHeuristic));
        }
    }
    return results;
}
function ask(rl, question) {
    return new Promise((resolve) => rl.question(question, resolve));
}
// Update squad.yaml with new hierarchy fields, remove old 'group' field
function updateSquadYaml(squadDir, setor, grupo, sessao) {
    const yamlPath = path.join(squadDir, 'squad.yaml');
    const raw = fs.readFileSync(yamlPath, 'utf-8');
    const parsed = yaml.load(raw);
    parsed.squad.setor = setor;
    parsed.squad.grupo = grupo;
    parsed.squad.sessao = sessao;
    delete parsed.squad.group; // remove deprecated field
    fs.writeFileSync(yamlPath, yaml.dump(parsed), 'utf-8');
}
// Update cross-squad path references in ALL squad.yaml files after a squad moved
function updateCrossReferences(squadsDir, oldPath, newPath) {
    const crossFields = ['design_system', 'brand_guidelines', 'assets_path'];
    // Get the old relative path from project root (e.g., "squads/design-system/...")
    // oldPath is absolute; we need relative from cwd
    const cwd = process.cwd();
    const oldRel = path.relative(cwd, oldPath).replace(/\\/g, '/');
    const newRel = path.relative(cwd, newPath).replace(/\\/g, '/');
    function walkForYaml(dir) {
        let entries;
        try {
            entries = fs.readdirSync(dir, { withFileTypes: true });
        }
        catch {
            return;
        }
        for (const entry of entries) {
            if (!entry.isDirectory())
                continue;
            if (entry.name.startsWith('.') || entry.name.startsWith('_'))
                continue;
            const fullPath = path.join(dir, entry.name);
            const yamlPath = path.join(fullPath, 'squad.yaml');
            if (fs.existsSync(yamlPath)) {
                try {
                    const raw = fs.readFileSync(yamlPath, 'utf-8');
                    const parsed = yaml.load(raw);
                    let changed = false;
                    for (const field of crossFields) {
                        const val = parsed.squad?.[field];
                        if (typeof val === 'string' && val.startsWith(oldRel)) {
                            parsed.squad[field] = val.replace(oldRel, newRel);
                            changed = true;
                        }
                    }
                    if (changed) {
                        fs.writeFileSync(yamlPath, yaml.dump(parsed), 'utf-8');
                    }
                }
                catch {
                    // Skip
                }
                // Don't recurse into squad dirs
            }
            else {
                walkForYaml(fullPath);
            }
        }
    }
    walkForYaml(squadsDir);
}
export async function reorganizeCommand() {
    const cwd = process.cwd();
    const squadsDir = path.join(cwd, 'squads');
    if (!fs.existsSync(squadsDir)) {
        console.error('No squads directory found. Run `expxagents init` first.');
        process.exit(1);
    }
    console.log('Escaneando squads...\n');
    const allSquads = discoverAllSquads(squadsDir);
    if (allSquads.length === 0) {
        console.log('Nenhuma squad encontrada.');
        return;
    }
    // Separate squads that already have hierarchy
    const alreadyClassified = allSquads.filter((s) => s.setor && s.grupo && s.sessao);
    const needClassification = allSquads.filter((s) => !s.setor || !s.grupo || !s.sessao);
    if (alreadyClassified.length > 0) {
        console.log(`${alreadyClassified.length} squad(s) já classificada(s) — sem alterações necessárias.`);
    }
    if (needClassification.length === 0) {
        console.log('Todas as squads já estão classificadas!');
        return;
    }
    console.log(`\n${needClassification.length} squad(s) precisam de classificação. Consultando IA...\n`);
    let inferences = [];
    try {
        inferences = await inferHierarchyWithClaude(needClassification);
    }
    catch (err) {
        console.error(`Falha ao consultar IA: ${err.message}`);
        console.log('Você precisará classificar manualmente cada squad.');
        inferences = [];
    }
    // Map inferences by code
    const inferenceMap = new Map(inferences.map((i) => [i.code, i]));
    const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
    const highConfidence = [];
    const lowConfidence = [];
    for (const squad of needClassification) {
        const inference = inferenceMap.get(squad.code);
        if (inference && inference.confidence === 'high') {
            highConfidence.push({ squad, setor: inference.setor, grupo: inference.grupo, sessao: inference.sessao });
        }
        else {
            lowConfidence.push(squad);
        }
    }
    // Show high-confidence inferences
    if (highConfidence.length > 0) {
        console.log('Inferências com alta confiança:');
        for (const c of highConfidence) {
            const newDir = `${c.setor}/${c.grupo}/${c.sessao}/${c.squad.code}`;
            console.log(`  ${c.squad.code}  →  ${newDir}`);
        }
        const confirm = await ask(rl, '\nConfirmar movimentações acima? [s/n]: ');
        if (confirm.trim().toLowerCase() !== 's') {
            console.log('Cancelado.');
            rl.close();
            return;
        }
    }
    // Collect manual classifications for low-confidence squads
    const manualClassifications = [];
    for (const squad of lowConfidence) {
        const inference = inferenceMap.get(squad.code);
        const suggestion = inference
            ? ` (sugestão: ${inference.setor}/${inference.grupo}/${inference.sessao})`
            : '';
        console.log(`\nClassificação necessária para: ${squad.code}${suggestion}`);
        console.log(`  Descrição: ${squad.description}`);
        const setor = (await ask(rl, '  Setor (ex: marketing, desenvolvimento, rh...): ')).trim();
        const grupo = (await ask(rl, '  Grupo: ')).trim();
        const sessao = (await ask(rl, '  Sessão: ')).trim();
        if (!setor || !grupo || !sessao) {
            console.log(`  Pulando ${squad.code} — classificação incompleta.`);
            continue;
        }
        manualClassifications.push({ squad, setor, grupo, sessao });
    }
    rl.close();
    const allClassified = [...highConfidence, ...manualClassifications];
    if (allClassified.length === 0) {
        console.log('\nNenhuma squad para mover.');
        return;
    }
    // Show dry-run summary
    console.log('\nPlano de reorganização:');
    for (const c of allClassified) {
        console.log(`  ${path.relative(squadsDir, c.squad.dir)}  →  ${c.setor}/${c.grupo}/${c.sessao}/${c.squad.code}`);
    }
    const rl2 = readline.createInterface({ input: process.stdin, output: process.stdout });
    const finalConfirm = await ask(rl2, '\nExecutar reorganização? [s/n]: ');
    rl2.close();
    if (finalConfirm.trim().toLowerCase() !== 's') {
        console.log('Cancelado.');
        return;
    }
    // Execute moves
    console.log('\nMovendo squads...');
    const moved = [];
    for (const c of allClassified) {
        const newDir = path.join(squadsDir, c.setor, c.grupo, c.sessao, c.squad.code);
        if (c.squad.dir === newDir) {
            console.log(`  ${c.squad.code} — já está no local correto.`);
            continue;
        }
        try {
            fs.mkdirSync(path.dirname(newDir), { recursive: true });
            fs.renameSync(c.squad.dir, newDir);
            updateSquadYaml(newDir, c.setor, c.grupo, c.sessao);
            moved.push({ squad: c.squad, newDir });
            console.log(`  ✓ ${c.squad.code} → ${c.setor}/${c.grupo}/${c.sessao}/${c.squad.code}`);
        }
        catch (err) {
            console.error(`  ✗ ${c.squad.code} — falha ao mover: ${err.message}`);
            console.error('    Squads movidas até agora foram mantidas. Corrija o erro e reexecute.');
        }
    }
    // Update cross-references for moved squads
    if (moved.length > 0) {
        console.log('\nAtualizando referências cruzadas...');
        for (const { squad, newDir } of moved) {
            updateCrossReferences(squadsDir, squad.dir, newDir);
        }
    }
    console.log('\nReorganização concluída!');
}
