from __future__ import annotations

import json
import shutil
from datetime import datetime
from pathlib import Path
from typing import Any

from liverylab_core import back_to_default, multiplayer_safety
from liverylab_core.game_file_writer import GameFileWriter
from liverylab_core.game_write_guard import require_game_write_ready


def session_dir(user_data_root: str | Path) -> Path:
    base = Path(user_data_root) / "PackageRefreshPrep" / datetime.now().strftime("%Y%m%d_%H%M%S")
    target = base
    index = 1
    while target.exists():
        index += 1
        target = base.with_name(f"{base.name}_{index}")
    target.mkdir(parents=True, exist_ok=True)
    return target


def write_manifest(folder: str | Path, manifest: dict[str, Any]) -> Path:
    path = Path(folder) / "package_refresh_prepare_manifest.json"
    path.write_text(json.dumps(_json_ready(manifest), indent=2, ensure_ascii=False), encoding="utf-8")
    return path


def _json_ready(value: Any) -> Any:
    if isinstance(value, Path):
        return str(value)
    if isinstance(value, dict):
        return {str(key): _json_ready(item) for key, item in value.items()}
    if isinstance(value, list):
        return [_json_ready(item) for item in value]
    if isinstance(value, tuple):
        return [_json_ready(item) for item in value]
    return value


def _writer_changed_count(result: dict[str, Any]) -> int:
    writer = result.get("writer") if isinstance(result.get("writer"), dict) else {}
    rows = writer.get("results") if isinstance(writer.get("results"), list) else []
    return sum(1 for row in rows if isinstance(row, dict) and str(row.get("status") or "") in {"written", "deleted"})


def _remove_safety_localization(p: dict[str, Path], writer: GameFileWriter) -> list[dict[str, Any]]:
    rows: list[dict[str, Any]] = []
    for locale in sorted(multiplayer_safety.LOCALIZATION_TEXT):
        path = p["localization"] / f"{locale}.loc"
        if not path.exists() or not path.is_file():
            rows.append({"locale": locale, "path": str(path), "changed": False, "skipped": "missing"})
            continue
        text = path.read_text(encoding="utf-8", errors="replace")
        lines = text.splitlines()
        keys = {multiplayer_safety.TITLE_LOC_KEY, multiplayer_safety.MESSAGE_LOC_KEY}
        kept = [line for line in lines if not any(line.startswith(f"{key}=") for key in keys)]
        changed = len(kept) != len(lines)
        if changed:
            newline = "\r\n" if "\r\n" in text else "\n"
            out_text = newline.join(kept)
            if kept and text.endswith(("\r\n", "\n")):
                out_text += newline
            writer.write_bytes(path, out_text.encode("utf-8"), label="remove LiveryLab Safety localization", backup=False)
        rows.append({"locale": locale, "path": str(path), "changed": changed})
    return rows


def cleanup_liverylab_safety_no_backup(root: str | Path) -> dict[str, Any]:
    p = multiplayer_safety.paths(root)
    before = multiplayer_safety.status(p["root"])
    require_game_write_ready(p["root"], "remove LiveryLab Safety", [p["ui"]], require_content_cars=False)
    writer = GameFileWriter(
        p["root"],
        "remove LiveryLab Safety",
        [p["ui"]],
        backup_root=None,
        require_content_cars=False,
    )
    if p["multiplayer"].exists():
        html = p["multiplayer"].read_text(encoding="utf-8", errors="ignore")
        patched = multiplayer_safety.SMOKE_SCRIPT_RE.sub("", html)
        patched = multiplayer_safety.SAFETY_SCRIPT_RE.sub("", patched)
        patched = multiplayer_safety.UNSAFE_SKINS_SCRIPT_RE.sub("", patched)
        if patched != html:
            writer.write_bytes(p["multiplayer"], patched.encode("utf-8"), label="remove LiveryLab Safety hook", backup=False)
    writer.delete_file(p["safety_js"], label="LiveryLab Safety script", backup=False)
    writer.delete_file(p["unsafe_skins_js"], label="LiveryLab Safety skin manifest script", backup=False)
    writer.delete_file(p["smoke_js"], label="old LiveryLab Safety smoke script", backup=False)
    writer.delete_file(p["manifest"], label="LiveryLab Safety manifest", backup=False)
    localization = _remove_safety_localization(p, writer)
    safety_dir_deleted = False
    if p["safety_dir"].exists() and p["safety_dir"].is_dir() and back_to_default.delete_path_allowed(p["root"], p["safety_dir"]):
        shutil.rmtree(p["safety_dir"])
        safety_dir_deleted = True
    return {
        "before": before,
        "after": multiplayer_safety.status(p["root"]),
        "writer": writer.to_dict(),
        "localization": localization,
        "safetyDirDeleted": safety_dir_deleted,
        "cleanupCount": _writer_changed_count({"writer": writer.to_dict()}) + int(safety_dir_deleted),
    }


def cleanup_runtime_hooks_no_backup(root: str | Path, library_root: str | Path) -> dict[str, Any]:
    game_root = Path(root)
    grid = back_to_default.cleanup_grid_bridge_no_backup(game_root)
    specs = back_to_default.cleanup_ai_vehicle_specs_no_backup(game_root, library_root)
    safety = cleanup_liverylab_safety_no_backup(game_root)
    grid_count = int(grid.get("bridgeWriteCount") or 0) + int(grid.get("nameCleanupWriteCount") or 0)
    return {
        "grid": grid,
        "aiVehicleSpecs": specs,
        "liverylabSafety": safety,
        "cleanupCount": grid_count + int(specs.get("cleanupCount") or 0) + int(safety.get("cleanupCount") or 0),
    }
