"""Serializes UMC data back to the KeyValues format and writes it to disk, with backup support."""

import shutil
from datetime import UTC, datetime
from pathlib import Path
from typing import Any

from core import constants
from core.domain.validator import validate_category_options, validate_map_options
from core.logger_config import logger
from core.utils import sanitize_kv_value

TAB = "\t"


# ==========================================================================
# 1. GESTION DES BACKUPS (Responsabilité : Cycle de vie des fichiers)
# ==========================================================================
def _rotate_and_create_backup(source_file: Path) -> Path:
    """Manages the rotation of old files and creates a backup of the source file."""
    constants.BACKUP_FOLDER.mkdir(parents=True, exist_ok=True)

    backups = sorted(constants.BACKUP_FOLDER.glob("*.txt"), key=lambda f: f.stat().st_mtime)
    while len(backups) >= constants.MAX_BACKUPS:
        oldest = backups.pop(0)
        oldest.unlink()
        logger.info(f"Old backup deleted : {oldest.name}")

    timestamp = datetime.now(tz=UTC).strftime("%Y-%m-%d_%H-%M-%S")
    backup_file = constants.BACKUP_FOLDER / f"umc_mapcycle_backup_{timestamp}.txt"

    shutil.copy2(source_file, backup_file)
    return backup_file


# ==========================================================================
# 2. SÉRIALISATION & FORMATTAGE (Responsabilité : Génération de texte clé valeur)
# ==========================================================================


def _format_block(name: str, data: dict[str, Any], indent_level: int) -> list[str]:
    """Generates a clean, generically indented KeyValue block (Category or Map).."""
    indent = TAB * indent_level
    inner_indent = TAB * (indent_level + 1)

    if "maps" not in data and not data:
        return [f'{indent}"{name}" {{}}']

    block = [f'{indent}"{name}"', f"{indent}{{"]

    if "options" in data:
        for key, value in data["options"].items():
            safe_value = sanitize_kv_value(value)
            block.append(f'{inner_indent}"{key}" "{safe_value}"')

        if data["options"] and data.get("maps"):
            block.append("")

        for map_name, map_options in data.get("maps", {}).items():
            block.extend(_format_block(map_name, map_options, indent_level + 1))

    else:
        for key, value in data.items():
            safe_value = sanitize_kv_value(value)
            block.append(f'{inner_indent}"{key}" "{safe_value}"')

    block.append(f"{indent}}}")
    return block


def _build_umc_content(umc_data: dict[str, Any]) -> str:
    """Builds the final raw string in UMC format."""
    lines = ['"umc_mapcycle"', "{"]

    for category_name, category_data in umc_data.items():
        lines.extend(_format_block(category_name, category_data, indent_level=1))

    lines.append("}")
    return "\n".join(lines)


# ==========================================================================
# 3. VERIFICATION DE L'INTÉGRITÉ (Responsabilité : Sécurité des données)
# ==========================================================================


def _validate_umc_data_integrity(umc_data: dict[str, Any]) -> None:
    """Checks the validity of in-memory data structures before writing."""
    for cat_data in umc_data.values():
        validate_category_options(cat_data.get("options", {}))
        for map_options in cat_data.get("maps", {}).values():
            validate_map_options(map_options)


# ==========================================================================
# 4. POINT D'ENTRÉE PUBLIC (Responsabilité : Persistance)
# ==========================================================================
def write(destination: str | Path, umc_data: dict[str, Any], create_backup: bool = True) -> None:
    """Validates the data, manages the backup, and writes the UMC configuration to disk."""
    destination = Path(destination)

    _validate_umc_data_integrity(umc_data)

    if create_backup and destination.exists():
        _rotate_and_create_backup(destination)

    content = _build_umc_content(umc_data)

    with destination.open("w", encoding="utf-8") as f:
        f.write(content)
