import { promises as fs } from 'node:fs';
import path from 'node:path';
import { messages } from '../../core/messages/index.js';
import { TUTANUS_ARQUIVOS } from '../../core/registry/index.js';
import { lerEstado, salvarEstado } from '../../shared/persistence/index.js';
const { log, logAuto, MapaReversaoExtraMensagens } = messages;
const CONSTANTES_MAPA = {
    VERSAO: '1.0.0',
    ID_LENGTH: 9,
    ID_OFFSET: 2,
    RADIX_36: 36
};
export class GerenciadorMapaReversao {
    mapaPath;
    mapa;
    constructor(opts) {
        this.mapaPath = opts?.mapaPath ?? TUTANUS_ARQUIVOS.MAPA_REVERSAO;
        this.mapa = {
            versao: CONSTANTES_MAPA.VERSAO,
            moves: [],
            metadata: {
                totalMoves: 0,
                ultimoMove: '',
                podeReverter: true
            }
        };
    }
    async carregar() {
        try {
            this.mapa = (await lerEstado(this.mapaPath, null)) ?? {
                versao: CONSTANTES_MAPA.VERSAO,
                moves: [],
                metadata: {
                    totalMoves: 0,
                    ultimoMove: '',
                    podeReverter: true
                }
            };
            if (!this.mapa.moves || !Array.isArray(this.mapa.moves)) {
                throw new Error(messages.ExcecoesMensagens.mapaReversaoCorrompido);
            }
            logAuto.mapaReversaoCarregado(this.mapa.moves.length);
        }
        catch (error) {
            if (error.code === 'ENOENT') {
                logAuto.mapaReversaoNenhumEncontrado();
            }
            else {
                logAuto.mapaReversaoErroCarregar(error.message);
                this.mapa = {
                    versao: CONSTANTES_MAPA.VERSAO,
                    moves: [],
                    metadata: {
                        totalMoves: 0,
                        ultimoMove: '',
                        podeReverter: true
                    }
                };
            }
        }
    }
    async salvar() {
        try {
            await fs.mkdir(path.dirname(this.mapaPath), {
                recursive: true
            });
            await salvarEstado(this.mapaPath, this.mapa);
            log.info(MapaReversaoExtraMensagens.mapaSalvo.replace('{total}', String(this.mapa.moves.length)));
        }
        catch (error) {
            logAuto.mapaReversaoErroSalvar(error.message);
        }
    }
    async registrarMove(origem, destino, motivo, conteudoOriginal, conteudoFinal, skipSalvar) {
        try {
            const id = `move_${Date.now()}_${Math.random().toString(CONSTANTES_MAPA.RADIX_36).substr(CONSTANTES_MAPA.ID_OFFSET, CONSTANTES_MAPA.ID_LENGTH)}`;
            const move = {
                id,
                timestamp: new Date().toISOString(),
                origem,
                destino,
                motivo,
                importsReescritos: !!conteudoOriginal || !!conteudoFinal && conteudoOriginal !== conteudoFinal,
                conteudoOriginal,
                conteudoFinal
            };
            this.mapa.moves.push(move);
            this.mapa.metadata.totalMoves = this.mapa.moves.length;
            this.mapa.metadata.ultimoMove = move.timestamp;
            if (!skipSalvar) {
                await this.salvar();
            }
            log.info(MapaReversaoExtraMensagens.moveRegistrado.replace('{origem}', origem).replace('{destino}', destino).replace('{motivo}', motivo));
            return id;
        }
        catch (err) {
            logAuto.mapaReversaoErroSalvar(err.message);
            throw err;
        }
    }
    async removerMove(id) {
        try {
            const indice = this.mapa.moves.findIndex((move) => move.id === id);
            if (indice === -1) {
                return false;
            }
            this.mapa.moves.splice(indice, 1);
            this.mapa.metadata.totalMoves = this.mapa.moves.length;
            await this.salvar();
            logAuto.moveRemovido(id);
            return true;
        }
        catch (err) {
            logAuto.mapaReversaoErroSalvar(err.message);
            return false;
        }
    }
    obterMoves() {
        return [...this.mapa.moves];
    }
    obterMovesPorArquivo(arquivo) {
        return this.mapa.moves.filter((move) => move.origem === arquivo || move.destino === arquivo);
    }
    podeReverterArquivo(arquivo) {
        const moves = this.obterMovesPorArquivo(arquivo);
        return moves.length > 0;
    }
    async reverterMove(id, baseDir = process.cwd()) {
        const move = this.mapa.moves.find((metrica) => metrica.id === id);
        if (!move) {
            logAuto.mapaReversaoMoveNaoEncontrado(id);
            return false;
        }
        try {
            const destinoCaminho = path.join(baseDir, move.destino);
            const origemCaminho = path.join(baseDir, move.origem);
            await fs.mkdir(path.dirname(origemCaminho), {
                recursive: true
            });
            if (move.importsReescritos && move.conteudoOriginal) {
                try {
                    await fs.writeFile(origemCaminho, move.conteudoOriginal, {
                        encoding: 'utf-8',
                        flag: 'wx'
                    });
                }
                catch (err) {
                    const code = err.code;
                    if (code === 'EEXIST') {
                        logAuto.mapaReversaoArquivoExisteOrigem(move.origem);
                        return false;
                    }
                    if (err?.code && err.code !== 'ENOENT') {
                        logAuto.mapaReversaoErroReverter(err.message);
                        return false;
                    }
                    throw err;
                }
                try {
                    await fs.unlink(destinoCaminho);
                }
                catch (err) {
                    if (err?.code === 'ENOENT') {
                        logAuto.mapaReversaoArquivoDestinoNaoEncontrado(move.destino);
                        return false;
                    }
                    throw err;
                }
                log.sucesso(MapaReversaoExtraMensagens.arquivoRevertidoConteudo.replace('{destino}', move.destino).replace('{origem}', move.origem));
            }
            else {
                try {
                    await fs.rename(destinoCaminho, origemCaminho);
                }
                catch (err) {
                    const code = err.code;
                    if (code === 'ENOENT') {
                        logAuto.mapaReversaoArquivoDestinoNaoEncontrado(move.destino);
                        return false;
                    }
                    if (code === 'EEXIST') {
                        logAuto.mapaReversaoArquivoExisteOrigem(move.origem);
                        return false;
                    }
                    throw err;
                }
                log.sucesso(MapaReversaoExtraMensagens.arquivoRevertido.replace('{destino}', move.destino).replace('{origem}', move.origem));
            }
            await this.removerMove(id);
            return true;
        }
        catch (error) {
            logAuto.mapaReversaoErroReverter(error.message);
            return false;
        }
    }
    async reverterArquivo(arquivo, baseDir = process.cwd()) {
        const moves = this.obterMovesPorArquivo(arquivo);
        if (moves.length === 0) {
            logAuto.mapaReversaoNenhumMove(arquivo);
            return false;
        }
        const movesOrdenados = moves.sort((arquivo, base) => new Date(base.timestamp).getTime() - new Date(arquivo.timestamp).getTime());
        let revertedContagem = 0;
        try {
            for (const move of movesOrdenados) {
                const resultado = await this.reverterMove(move.id, baseDir);
                if (resultado)
                    revertedContagem += 1;
            }
        }
        catch (error) {
            logAuto.mapaReversaoErroReverter(error.message);
            return false;
        }
        return revertedContagem > 0;
    }
    listarMoves() {
        if (this.mapa.moves.length === 0) {
            return MapaReversaoExtraMensagens.nenhumMoveRegistrado;
        }
        let resultado = MapaReversaoExtraMensagens.tituloMapa.replace('{total}', String(this.mapa.moves.length));
        const movesOrdenados = [...this.mapa.moves].sort((arquivo, base) => new Date(base.timestamp).getTime() - new Date(arquivo.timestamp).getTime());
        for (const move of movesOrdenados) {
            const dataFormatada = new Date(move.timestamp).toLocaleString('pt-BR');
            const reescritos = move.importsReescritos ? ' (imports reescritos)' : '';
            resultado += `${move.id}:\n`;
            resultado += `  [DATE] ${dataFormatada}\n`;
            resultado += `  [FOLDER] ${move.origem} → ${move.destino}\n`;
            resultado += `  [COMENTARIO] ${move.motivo}${reescritos}\n\n`;
        }
        return resultado;
    }
    async limpar() {
        try {
            this.mapa.moves = [];
            this.mapa.metadata.totalMoves = 0;
            this.mapa.metadata.ultimoMove = '';
            await this.salvar();
            log.info(MapaReversaoExtraMensagens.mapaLimpo);
        }
        catch (err) {
            logAuto.mapaReversaoErroSalvar(err.message);
        }
    }
}
export const mapaReversao = new GerenciadorMapaReversao();
//# sourceMappingURL=map-reversion.js.map