import 'dotenv/config';
import fs from 'node:fs';
import path from 'node:path';
import { analistaGithubActions, analistaGithubActionsGlobal, autofixEngine, gerarRelatorio, obterDetectoresGithubActions, pontuarWorkflow, prepararDadosRelatorio } from '../../analysts/github-actions/index.js';
import { iniciarServidorApp } from '../../app/github/app/index.js';
import { ExitCode, sair } from '../helpers/index.js';
import { aplicarCorrecoes, salvarArquivoCorrigido } from '../../core/execution/index.js';
import { CliComandoGithubActionsMensagens, messages } from '../../core/messages/index.js';
import { Command } from 'commander';
import ora from 'ora';
const SCORE_MAX = 100;
const SCORE_MIN = 0;
const PENALTY_PER_OCCURRENCE = 5;
const DEFAULT_GATE_THRESHOLD = 70;
const log = messages.log;
function normalizarOcorrencias(result) {
    if (!result)
        return [];
    return Array.isArray(result) ? result : [result];
}
function lerDiretorioWorkflows(workflowDir) {
    try {
        return fs.readdirSync(workflowDir).filter(arquivo => arquivo.endsWith('.yml') || arquivo.endsWith('.yaml'));
    }
    catch {
        return [];
    }
}
function lerArquivoWorkflow(wfPath) {
    try {
        return fs.readFileSync(wfPath, 'utf-8');
    }
    catch {
        return null;
    }
}
function montarContextoExecucao(workflowDir, workflowFiles) {
    return {
        baseDir: workflowDir,
        arquivos: workflowFiles.map(wf => ({
            relPath: `.github/workflows/${wf}`,
            content: fs.readFileSync(path.join(workflowDir, wf), 'utf-8'),
            ast: null,
            fullCaminho: `.github/workflows/${wf}`
        }))
    };
}
function criarContextArquivo(wf, conteudo, workflowDir) {
    const relPath = `.github/workflows/${wf}`;
    return {
        baseDir: workflowDir,
        arquivos: [{
                relPath,
                content: conteudo,
                ast: null,
                fullCaminho: relPath
            }]
    };
}
async function processarWorkflows(workflowDir, workflowFiles) {
    const startTime = Date.now();
    const todasOcorrencias = [];
    const workflowsInfo = [];
    for (const wf of workflowFiles) {
        const wfPath = path.join(workflowDir, wf);
        const conteudo = fs.readFileSync(wfPath, 'utf-8');
        const relPath = `.github/workflows/${wf}`;
        const context = criarContextArquivo(wf, conteudo, workflowDir);
        const result = await analistaGithubActions.aplicar(conteudo, relPath, null, undefined, context);
        const ocorrencias = normalizarOcorrencias(result);
        const scoreResult = pontuarWorkflow(conteudo, relPath);
        workflowsInfo.push({ nome: wf, score: scoreResult.percentage, ocorrencias: ocorrencias.length });
        todasOcorrencias.push(...ocorrencias);
    }
    const contextGlobal = montarContextoExecucao(workflowDir, workflowFiles);
    const resultGlobal = await analistaGithubActionsGlobal.aplicar('', '', null, undefined, contextGlobal);
    todasOcorrencias.push(...normalizarOcorrencias(resultGlobal));
    const tempoAnalise = Date.now() - startTime;
    return { todasOcorrencias, workflowsInfo, tempoAnalise };
}
function calcularScoreGeral(workflowsInfo) {
    return workflowsInfo.length > 0
        ? Math.round(workflowsInfo.reduce((sum, item) => sum + item.score, 0) / workflowsInfo.length)
        : 100;
}
export function comandoGithubActions() {
    const cmd = new Command('github-actions').alias('gha').description(CliComandoGithubActionsMensagens.descricaoCmd);
    cmd.command('scan').alias('s').description(CliComandoGithubActionsMensagens.descricaoScan)
        .option('-p, --path <caminho>', CliComandoGithubActionsMensagens.optPath, '.')
        .option('-w, --workflow <arquivo>', CliComandoGithubActionsMensagens.optWorkflow)
        .option('-j, --json', 'Saída em JSON')
        .option('--compact', 'Saída compacta')
        .option('--fix', CliComandoGithubActionsMensagens.optFix)
        .option('--dry-run', CliComandoGithubActionsMensagens.optDryRun)
        .action(async (opts) => {
        const repoPath = path.resolve(opts.path || '.');
        const workflowDir = path.join(repoPath, '.github', 'workflows');
        const workflowFilesContent = lerDiretorioWorkflows(workflowDir);
        if (workflowFilesContent.length === 0) {
            log.erro(CliComandoGithubActionsMensagens.workflowDirNaoEncontrado);
            sair(ExitCode.Failure);
            return;
        }
        let workflowFiles;
        if (opts.workflow) {
            const wfPath = path.join(workflowDir, opts.workflow);
            if (lerArquivoWorkflow(wfPath) === null) {
                log.erro(CliComandoGithubActionsMensagens.workflowNaoEncontrado(opts.workflow));
                sair(ExitCode.Failure);
                return;
            }
            workflowFiles = [opts.workflow];
        }
        else {
            workflowFiles = workflowFilesContent;
        }
        if (workflowFiles.length === 0) {
            log.info(CliComandoGithubActionsMensagens.nenhumWorkflowEncontrado);
            return;
        }
        const spinner = opts.json ? {
            text: '',
            start: () => spinner,
            succeed: () => spinner,
            fail: () => spinner
        } : ora({ text: 'Analisando workflows...', spinner: 'dots' }).start();
        try {
            const startTime = Date.now();
            const todasOcorrencias = [];
            const workflowsInfo = [];
            for (const wf of workflowFiles) {
                const wfPath = path.join(workflowDir, wf);
                const conteudo = fs.readFileSync(wfPath, 'utf-8');
                const relPath = `.github/workflows/${wf}`;
                const context = criarContextArquivo(wf, conteudo, workflowDir);
                const result = await analistaGithubActions.aplicar(conteudo, relPath, null, undefined, context);
                const ocorrencias = normalizarOcorrencias(result);
                if (opts.fix) {
                    const ocorrenciasComFix = ocorrencias.filter(ocorrencia => !!ocorrencia.correcao);
                    let conteudoAtualizado = conteudo;
                    if (ocorrenciasComFix.length > 0) {
                        conteudoAtualizado = aplicarCorrecoes(conteudo, ocorrenciasComFix);
                    }
                    const detectores = obterDetectoresGithubActions();
                    const fixers = autofixEngine.extrairFixers(detectores);
                    if (fixers.length > 0) {
                        conteudoAtualizado = autofixEngine.aplicarFixes(conteudoAtualizado, fixers);
                    }
                    if (conteudoAtualizado !== conteudo) {
                        if (opts.dryRun) {
                            log.info(CliComandoGithubActionsMensagens.dryRunAlteracoes(wf));
                            log.info(conteudoAtualizado);
                        }
                        else {
                            salvarArquivoCorrigido(wfPath, conteudoAtualizado);
                            log.sucesso(CliComandoGithubActionsMensagens.correcoesAplicadas(wf));
                        }
                    }
                }
                const score = Math.max(SCORE_MIN, SCORE_MAX - ocorrencias.length * PENALTY_PER_OCCURRENCE);
                workflowsInfo.push({ nome: wf, score, ocorrencias: ocorrencias.length });
                todasOcorrencias.push(...ocorrencias);
            }
            const contextGlobal = montarContextoExecucao(workflowDir, workflowFiles);
            const resultGlobal = await analistaGithubActionsGlobal.aplicar('', '', null, undefined, contextGlobal);
            todasOcorrencias.push(...normalizarOcorrencias(resultGlobal));
            const tempoAnalise = Date.now() - startTime;
            const scoreGeral = calcularScoreGeral(workflowsInfo);
            spinner.succeed(CliComandoGithubActionsMensagens.analiseConcluida(workflowFiles.length, todasOcorrencias.length));
            if (opts.json) {
                const dados = prepararDadosRelatorio(todasOcorrencias, path.basename(repoPath), tempoAnalise, workflowsInfo);
                console.log(JSON.stringify(dados, null, 2));
                return;
            }
            if (opts.compact) {
                log.info(CliComandoGithubActionsMensagens.scoreCompacto(scoreGeral, workflowFiles.length, todasOcorrencias.length));
                return;
            }
            log.info(CliComandoGithubActionsMensagens.scoreGeral(scoreGeral));
            log.info(CliComandoGithubActionsMensagens.workflowsAnalisados(workflowFiles.length));
            log.info(CliComandoGithubActionsMensagens.totalOcorrencias(todasOcorrencias.length));
            log.info(CliComandoGithubActionsMensagens.tempoAnalise(tempoAnalise));
            log.info(CliComandoGithubActionsMensagens.workflowsTitulo);
            for (const wf of workflowsInfo) {
                const icon = wf.score >= 80 ? '[OK]' : wf.score >= 50 ? '[AVISO]' : '[ERRO]';
                log.info(CliComandoGithubActionsMensagens.workflowItem(icon, wf.nome, wf.score, wf.ocorrencias));
            }
            if (todasOcorrencias.length > 0) {
                log.info(CliComandoGithubActionsMensagens.ocorrenciasTitulo);
                for (const ocorrencia of todasOcorrencias.slice(0, 20)) {
                    const nivel = ocorrencia.nivel || 'info';
                    const nivelIcon = nivel === 'erro' ? '[RED]' : nivel === 'aviso' ? '[YELLOW]' : '[BLUE]';
                    log.info(CliComandoGithubActionsMensagens.ocorrenciaItem(nivelIcon, ocorrencia.relPath, ocorrencia.linha ?? 0, ocorrencia.mensagem));
                }
                if (todasOcorrencias.length > 20) {
                    log.info(CliComandoGithubActionsMensagens.maisOcorrencias(todasOcorrencias.length - 20));
                }
            }
        }
        catch (err) {
            spinner.fail(CliComandoGithubActionsMensagens.erroAnalise);
            log.erro(err instanceof Error ? err.message : String(err));
            sair(ExitCode.Failure);
        }
    });
    cmd.command('report').alias('r').description(CliComandoGithubActionsMensagens.descricaoReport)
        .option('-p, --path <caminho>', CliComandoGithubActionsMensagens.optPath, '.')
        .option('-f, --format <formato>', 'Formato do relatório (json, markdown, html, csv)', 'markdown')
        .option('-o, --output <arquivo>', 'Arquivo de saída')
        .option('--titulo <titulo>', 'Título do relatório')
        .option('--no-detalhes', CliComandoGithubActionsMensagens.optNoDetalhes)
        .action(async (opts) => {
        const repoPath = path.resolve(opts.path || '.');
        const workflowDir = path.join(repoPath, '.github', 'workflows');
        const workflowFiles = lerDiretorioWorkflows(workflowDir);
        if (workflowFiles.length === 0) {
            log.erro(CliComandoGithubActionsMensagens.workflowDirNaoEncontrado);
            sair(ExitCode.Failure);
            return;
        }
        const formato = opts.format;
        if (!['json', 'markdown', 'html', 'csv'].includes(formato)) {
            log.erro(CliComandoGithubActionsMensagens.formatoInvalido(formato));
            sair(ExitCode.Failure);
            return;
        }
        const spinner = ora({ text: 'Gerando relatório...', spinner: 'dots' }).start();
        try {
            const { todasOcorrencias, workflowsInfo, tempoAnalise } = await processarWorkflows(workflowDir, workflowFiles);
            const output = opts.output || `github-actions-report.${formato === 'markdown' ? 'md' : formato}`;
            const dados = prepararDadosRelatorio(todasOcorrencias, path.basename(repoPath), tempoAnalise, workflowsInfo);
            await gerarRelatorio(dados, {
                formato,
                output,
                titulo: opts.titulo,
                incluirDetalhes: opts.detalhes !== false
            });
            spinner.succeed(CliComandoGithubActionsMensagens.relatorioGerado(output));
            log.info(CliComandoGithubActionsMensagens.formatoRelatorio(formato));
            log.info(CliComandoGithubActionsMensagens.scoreReport(dados.scoreGeral));
            log.info(CliComandoGithubActionsMensagens.ocorrenciasReport(todasOcorrencias.length));
        }
        catch (err) {
            spinner.fail(CliComandoGithubActionsMensagens.erroGerarRelatorio);
            log.erro(err instanceof Error ? err.message : String(err));
            sair(ExitCode.Failure);
        }
    });
    cmd.command('gate').alias('g').description(CliComandoGithubActionsMensagens.descricaoGate)
        .option('-p, --path <caminho>', CliComandoGithubActionsMensagens.optPath, '.')
        .option('-t, --threshold <numero>', 'Score mínimo aceitável (0-100)', DEFAULT_GATE_THRESHOLD.toString())
        .option('-w, --workflow <arquivo>', 'Verificar workflow específico')
        .option('-j, --json', 'Saída em JSON para consumo externo')
        .option('--fail-on <nivel>', 'Nível mínimo para falhar (erro, aviso, info)', 'erro')
        .action(async (opts) => {
        const repoPath = path.resolve(opts.path || '.');
        const workflowDir = path.join(repoPath, '.github', 'workflows');
        const threshold = parseInt(opts.threshold || DEFAULT_GATE_THRESHOLD.toString(), 10);
        const workflowFilesContent = lerDiretorioWorkflows(workflowDir);
        if (workflowFilesContent.length === 0) {
            if (opts.json) {
                console.log(JSON.stringify({ success: false, error: CliComandoGithubActionsMensagens.workflowDirNaoEncontrado }));
            }
            else {
                log.erro(CliComandoGithubActionsMensagens.workflowDirNaoEncontrado);
            }
            sair(ExitCode.Failure);
            return;
        }
        let workflowFiles;
        if (opts.workflow) {
            const wfPath = path.join(workflowDir, opts.workflow);
            if (lerArquivoWorkflow(wfPath) === null) {
                if (opts.json) {
                    console.log(JSON.stringify({ success: false, error: CliComandoGithubActionsMensagens.workflowNaoEncontrado(opts.workflow) }));
                }
                else {
                    log.erro(CliComandoGithubActionsMensagens.workflowNaoEncontrado(opts.workflow));
                }
                sair(ExitCode.Failure);
                return;
            }
            workflowFiles = [opts.workflow];
        }
        else {
            workflowFiles = workflowFilesContent;
        }
        if (workflowFiles.length === 0) {
            if (opts.json) {
                console.log(JSON.stringify({ success: true, score: SCORE_MAX, message: CliComandoGithubActionsMensagens.nenhumWorkflowEncontrado }));
            }
            else {
                log.info(CliComandoGithubActionsMensagens.nenhumWorkflowEncontrado);
            }
            return;
        }
        try {
            const { todasOcorrencias, workflowsInfo, tempoAnalise: _tempoAnalise } = await processarWorkflows(workflowDir, workflowFiles);
            const scoreGeral = calcularScoreGeral(workflowsInfo);
            const erros = todasOcorrencias.filter(ocorrencia => ocorrencia.nivel === 'erro').length;
            const avisos = todasOcorrencias.filter(ocorrencia => ocorrencia.nivel === 'aviso').length;
            let passou = true;
            const motivosFalha = [];
            if (scoreGeral < threshold) {
                passou = false;
                motivosFalha.push(`Score ${scoreGeral} abaixo do threshold ${threshold}`);
            }
            if (opts.failOn === 'erro' && erros > 0) {
                passou = false;
                motivosFalha.push(`${erros} erro(s) crítico(s) encontrado(s)`);
            }
            if (opts.failOn === 'aviso' && erros + avisos > 0) {
                passou = false;
                motivosFalha.push(`${erros + avisos} erro(s)/aviso(s) encontrado(s)`);
            }
            const resultado = {
                success: passou,
                score: scoreGeral,
                threshold,
                workflows: workflowsInfo,
                ocorrencias: {
                    total: todasOcorrencias.length,
                    erros,
                    avisos,
                    info: todasOcorrencias.filter(ocorrencia => ocorrencia.nivel === 'info').length
                },
                motivosFalha: passou ? [] : motivosFalha
            };
            if (opts.json) {
                console.log(JSON.stringify(resultado, null, 2));
            }
            else if (passou) {
                log.sucesso(CliComandoGithubActionsMensagens.gatePassou(scoreGeral, threshold));
            }
            else {
                log.erro(CliComandoGithubActionsMensagens.gateFalhou(scoreGeral, threshold));
                for (const motivo of motivosFalha) {
                    log.erro(CliComandoGithubActionsMensagens.gateFalhaMotivo(motivo));
                }
            }
            if (!passou)
                sair(ExitCode.Failure);
        }
        catch (err) {
            log.erro(err instanceof Error ? err.message : String(err));
            sair(ExitCode.Failure);
        }
    });
    cmd.command('app').description(CliComandoGithubActionsMensagens.descricaoApp)
        .option('-p, --port <number>', 'Porta do servidor', process.env.TUTANUS_API_PORT || process.env.PORT || '3000')
        .action(async (opts) => {
        const appId = process.env.GITHUB_APP_ID;
        const privateKey = process.env.GITHUB_PRIVATE_KEY;
        const webhookSecret = process.env.GITHUB_WEBHOOK_SECRET;
        if (!appId || !privateKey || !webhookSecret) {
            log.erro(CliComandoGithubActionsMensagens.appSetupRequired);
            log.erro('  - GITHUB_APP_ID');
            log.erro('  - GITHUB_PRIVATE_KEY');
            log.erro('  - GITHUB_WEBHOOK_SECRET');
            log.info(CliComandoGithubActionsMensagens.appDicaEnv);
            sair(ExitCode.Failure);
            return;
        }
        try {
            await iniciarServidorApp({
                appId,
                privateKey: privateKey.replace(/\\n/g, '\n'),
                webhookSecret,
                port: parseInt(opts.port, 10),
            });
        }
        catch (err) {
            log.erro(CliComandoGithubActionsMensagens.erroIniciarServidor(err instanceof Error ? err.message : String(err)));
            sair(ExitCode.Failure);
        }
    });
    return cmd;
}
//# sourceMappingURL=command-github-actions.js.map