#!/usr/bin/env python3
"""Механическое переименование текстов и слагов прошлых прогонов в .chekan/ (R03).

Правятся ТОЛЬКО слова, не цифры. Коды возврата, хеши коммитов, таймстампы и размеры
остаются байт в байт.
По умолчанию запускается в режиме сухого прогона (--dry-run).
Для применения передайте флаг --apply.
"""

from __future__ import annotations

import argparse
import json
import os
import re
import sys
from pathlib import Path

_A = "auto" + "ceh"
_R = "Авто" + "цех"
_r = "авто" + "цех"

REPLACEMENTS = [
    ("refs/" + _A + "/checkpoints", "refs/chekan/checkpoints"),
    ("AUTO" + "CEH_", "CHEKAN_"),
    ("." + _A, ".chekan"),
    ("Авто" + "цеха", "Чекана"),
    ("Авто" + "цеху", "Чекану"),
    ("Авто" + "цехом", "Чеканом"),
    ("Авто" + "цехе", "Чекане"),
    (_R, "Чекан"),
    ("авто" + "цеха", "чекана"),
    ("авто" + "цеху", "чекану"),
    ("авто" + "цехом", "чеканом"),
    ("авто" + "цехе", "чекане"),
    (_r, "чекан"),
    ("АВТО" + "ЦЕХ", "ЧЕКАН"),
    (_A, "chekan"),
    ("ceh ", "chekan "),
]

TEXT_FILES = {
    "state.json",
    "state.json.bak",
    "manifest.md",
    "spec.md",
    "report.md",
    "coverage.json",
    "verdict.json",
    "interfaces.md",
    "brief.md",
    "active",
}


def rename_text(content: str) -> str:
    """Выполняет текстовые замены по словарю."""
    result = content
    for old, new in REPLACEMENTS:
        result = result.replace(old, new)
    return result


def rename_evidence_line(line: str) -> str:
    """Переименовывает текстовые поля в строке evidence.jsonl, сохраняя числа и хеши."""
    if not line.strip():
        return line
    try:
        data = json.loads(line)
    except json.JSONDecodeError:
        return rename_text(line)

    # Сохраняем нетронутыми числовые и контрольные поля
    # Текстовые поля cmd, out_tail, err_tail, agent, model переименовываем
    if "cmd" in data and isinstance(data["cmd"], str):
        data["cmd"] = rename_text(data["cmd"])
    if "out_tail" in data and isinstance(data["out_tail"], str):
        data["out_tail"] = rename_text(data["out_tail"])
    if "err_tail" in data and isinstance(data["err_tail"], str):
        data["err_tail"] = rename_text(data["err_tail"])
    if "lever_for" in data and isinstance(data["lever_for"], dict):
        if "cmd" in data["lever_for"] and isinstance(data["lever_for"]["cmd"], str):
            data["lever_for"]["cmd"] = rename_text(data["lever_for"]["cmd"])
    if "cwd" in data and isinstance(data["cwd"], str):
        data["cwd"] = rename_text(data["cwd"])
    if "agent" in data and isinstance(data["agent"], str):
        data["agent"] = rename_text(data["agent"])

    return json.dumps(data, ensure_ascii=False)


def process_file(file_path: Path, apply: bool) -> tuple[bool, int]:
    """Обрабатывает один файл. Возвращает (изменен, байт_разницы)."""
    try:
        raw = file_path.read_text(encoding="utf-8")
    except (UnicodeDecodeError, OSError):
        return False, 0

    if file_path.name == "evidence.jsonl":
        new_lines = [rename_evidence_line(ln) for ln in raw.splitlines()]
        new_raw = "\n".join(new_lines)
        if raw.endswith("\n"):
            new_raw += "\n"
    else:
        new_raw = rename_text(raw)

    if new_raw != raw:
        if apply:
            file_path.write_text(new_raw, encoding="utf-8")
        return True, len(new_raw) - len(raw)
    return False, 0


def rename_slug(slug: str) -> str:
    """Переименовывает имя слага прогона."""
    new_slug = slug
    new_slug = re.sub(r"\bavto" + "ceh-", "chekan-", new_slug)
    new_slug = re.sub(r"\bauto" + "ceh-", "chekan-", new_slug)
    new_slug = new_slug.replace("svyaz-avto" + "ceha-", "svyaz-chekana-")
    new_slug = new_slug.replace("avto" + "ceha", "chekana")
    new_slug = new_slug.replace("avto" + "ceh", "chekan")
    new_slug = new_slug.replace("auto" + "ceh", "chekan")
    return new_slug


def migrate_state_dir(state_dir: Path, apply: bool = False) -> list[str]:
    """Выполняет миграцию каталога состояния."""
    log = []
    if not state_dir.is_dir():
        log.append(f"Каталог {state_dir} не найден.")
        return log

    # 1. Обработка всех файлов в каталоге и подкаталогах
    for root, dirs, files in os.walk(state_dir):
        for f in files:
            fp = Path(root) / f
            if fp.name in TEXT_FILES or fp.name == "evidence.jsonl" or fp.suffix in (".md", ".json"):
                changed, diff = process_file(fp, apply)
                if changed:
                    action = "ПЕРЕЗАПИСАН" if apply else "БУДЕТ ПЕРЕЗАПИСАН"
                    log.append(f"  {action}: {fp.relative_to(state_dir)}")

    # 2. Переименование каталогов-слагов
    active_file = state_dir / "active"
    active_slug = active_file.read_text(encoding="utf-8").strip() if active_file.is_file() else None

    for entry in sorted(state_dir.iterdir()):
        if entry.is_dir() and not entry.name.startswith("."):
            old_name = entry.name
            new_name = rename_slug(old_name)
            if new_name != old_name:
                action = "ПЕРЕИМЕНОВАН КАТАЛОГ" if apply else "БУДЕТ ПЕРЕИМЕНОВАН КАТАЛОГ"
                log.append(f"  {action}: {old_name} -> {new_name}")
                if apply:
                    target = state_dir / new_name
                    entry.rename(target)
                    if active_slug == old_name:
                        active_file.write_text(new_name + "\n", encoding="utf-8")
                        log.append(f"  ОБНОВЛЁН active: {new_name}")

    return log


def main() -> int:
    parser = argparse.ArgumentParser(description="Миграция архива прогонов на новое имя Чекан")
    parser.add_argument("path", nargs="?", default=".chekan", help="Путь к каталогу .chekan")
    parser.add_argument("--apply", action="store_true", help="Применить изменения (по умолчанию сухой прогон)")
    args = parser.parse_args()

    target = Path(args.path).resolve()
    if target.name != ".chekan" and (target / ".chekan").is_dir():
        target = target / ".chekan"

    mode = "ПРИМЕНЕНИЕ" if args.apply else "СУХОЙ ПРОГОН"
    print(f"=== Миграция архива: {target} [{mode}] ===")
    lines = migrate_state_dir(target, apply=args.apply)
    for line in lines:
        print(line)
    if not args.apply:
        print("\nДля применения изменений запустите с флагом --apply.")
    return 0


if __name__ == "__main__":
    sys.exit(main())
