"""Compacta JSONs persistidos sem alterar seu formato ou extensão."""
from __future__ import annotations

import json
import os
import sys
import tempfile
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent
if str(BASE_DIR) not in sys.path:
    sys.path.insert(0, str(BASE_DIR))

from app.settings import PASTA_BACKUPS, PASTA_BASE, PASTA_PROCESSAMENTOS, PASTA_RUNTIME, PASTA_UPLOADS_TEMP

PASTAS_DADOS = (PASTA_PROCESSAMENTOS, PASTA_RUNTIME, PASTA_BACKUPS, PASTA_BASE, PASTA_UPLOADS_TEMP)


def _arquivos_json() -> list[Path]:
    encontrados: set[Path] = set()
    for pasta in PASTAS_DADOS:
        if pasta.exists():
            encontrados.update(arquivo for arquivo in pasta.rglob("*.json") if arquivo.is_file())
    return sorted(encontrados)


def _ler_json(arquivo: Path):
    return json.loads(arquivo.read_text(encoding="utf-8-sig"))


def _compactar(arquivo: Path) -> tuple[int, int]:
    conteudo = json.dumps(_ler_json(arquivo), ensure_ascii=False, separators=(",", ":")) + "\n"
    antes = arquivo.stat().st_size
    depois = len(conteudo.encode("utf-8"))
    if depois >= antes:
        return antes, antes
    with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", dir=arquivo.parent, prefix=f".{arquivo.name}.", suffix=".tmp", delete=False) as temporario:
        temporario.write(conteudo)
        caminho_temporario = Path(temporario.name)
    os.replace(caminho_temporario, arquivo)
    return antes, depois


def main() -> int:
    arquivos = _arquivos_json()
    validos: list[Path] = []
    invalidos: list[tuple[Path, str]] = []
    # Valida tudo antes de escrever: nenhum arquivo é alterado se houver falha.
    for arquivo in arquivos:
        try:
            _ler_json(arquivo)
            validos.append(arquivo)
        except (OSError, UnicodeDecodeError, json.JSONDecodeError) as erro:
            invalidos.append((arquivo, str(erro)))
    if invalidos:
        print("[ERRO] JSON inválido; nenhuma compactação foi aplicada:")
        for arquivo, erro in invalidos:
            print(f"  - {arquivo}: {erro}")
    total_antes = total_depois = alterados = 0
    for arquivo in validos:
        antes, depois = _compactar(arquivo)
        total_antes += antes
        total_depois += depois
        alterados += int(depois < antes)
    poupado = total_antes - total_depois
    percentual = poupado / total_antes * 100 if total_antes else 0
    print(f"[OK] JSONs compactados: {alterados}/{len(validos)}; ignorados inválidos: {len(invalidos)}; economia: {poupado} bytes ({percentual:.1f}%).")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
