#!/usr/bin/env python3
"""Disable automatic chat-to-memory and chat-to-skill reinforcement for leoclean."""

from __future__ import annotations

import argparse
import json
import os
import shutil
import tempfile
from pathlib import Path
from typing import Any

import yaml

POLICY_VERSION = "teleo-leoclean-learning-policy-v1"
BACKUP_SUFFIX = ".before-teleo-learning-policy"
MEMORY_NUDGE_INTERVAL = 0
SKILL_CREATION_NUDGE_INTERVAL = 0


def _load_config(path: Path) -> dict[str, Any]:
    if path.is_symlink():
        raise ValueError("refusing symlinked profile config")
    raw = yaml.safe_load(path.read_text(encoding="utf-8")) or {}
    if not isinstance(raw, dict):
        raise ValueError("profile config must be a YAML mapping")
    return raw


def policy_projection(config: dict[str, Any]) -> dict[str, int | None]:
    memory = config.get("memory") if isinstance(config.get("memory"), dict) else {}
    skills = config.get("skills") if isinstance(config.get("skills"), dict) else {}
    return {
        "memory_nudge_interval": memory.get("nudge_interval"),
        "skill_creation_nudge_interval": skills.get("creation_nudge_interval"),
    }


def enforce_policy(path: Path, *, check: bool = False) -> tuple[dict[str, Any], int]:
    config = _load_config(path)
    before = policy_projection(config)
    expected = {
        "memory_nudge_interval": MEMORY_NUDGE_INTERVAL,
        "skill_creation_nudge_interval": SKILL_CREATION_NUDGE_INTERVAL,
    }
    changed = before != expected

    if check:
        return {
            "policy_version": POLICY_VERSION,
            "status": "change_required" if changed else "compliant",
            "target": str(path),
            "policy": before,
        }, 1 if changed else 0

    backup_path = path.with_name(path.name + BACKUP_SUFFIX)
    if changed:
        memory = config.setdefault("memory", {})
        skills = config.setdefault("skills", {})
        if not isinstance(memory, dict) or not isinstance(skills, dict):
            raise ValueError("memory and skills config sections must be YAML mappings")
        memory["nudge_interval"] = MEMORY_NUDGE_INTERVAL
        skills["creation_nudge_interval"] = SKILL_CREATION_NUDGE_INTERVAL

        if not backup_path.exists():
            shutil.copy2(path, backup_path)

        mode = path.stat().st_mode & 0o777
        rendered = yaml.safe_dump(config, sort_keys=False, allow_unicode=False)
        with tempfile.NamedTemporaryFile(
            "w", encoding="utf-8", dir=path.parent, prefix=f".{path.name}.", delete=False
        ) as handle:
            handle.write(rendered)
            temp_path = Path(handle.name)
        try:
            temp_path.chmod(mode)
            os.replace(temp_path, path)
        finally:
            temp_path.unlink(missing_ok=True)

    after = policy_projection(_load_config(path))
    if after != expected:
        raise ValueError("profile config did not retain the required learning policy")
    return {
        "policy_version": POLICY_VERSION,
        "status": "updated" if changed else "already_compliant",
        "target": str(path),
        "backup": str(backup_path) if changed else None,
        "policy": after,
    }, 0


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("target", type=Path)
    parser.add_argument("--check", action="store_true")
    args = parser.parse_args()
    try:
        result, code = enforce_policy(args.target, check=args.check)
    except (OSError, ValueError, yaml.YAMLError) as exc:
        result = {
            "policy_version": POLICY_VERSION,
            "status": "error",
            "target": str(args.target),
            "error": type(exc).__name__,
        }
        code = 2
    print(json.dumps(result, sort_keys=True))
    return code


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