#!/usr/bin/env python3
"""Apply a model profile to agent definition files.

Supports:
- OpenCode YAML frontmatter agents in .opencode/agents/*.md
- Codex TOML agents in codex_adapter_templates/codex/agents/*.toml
"""

from __future__ import annotations

import argparse
import re
import sys
from pathlib import Path


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

from scripts.lib.model_config import (
    ModelConfigError,
    parse_model_overrides,
    resolve_model_profile,
)

OPENCODE_ROLE_TO_FILE = {
    "dr_plan": ".opencode/agents/dr-plan.md",
    "dr_pm": ".opencode/agents/dr-pm.md",
    "dr_searcher": ".opencode/agents/dr-searcher.md",
    "dr_analyst": ".opencode/agents/dr-analyst.md",
    "dr_verifier": ".opencode/agents/dr-verifier.md",
    "dr_chief_editor": ".opencode/agents/dr-chief-editor.md",
    "dr_editor_in_chief": ".opencode/agents/dr-editor-in-chief.md",
    "dr_reporter": ".opencode/agents/dr-reporter.md",
}

CODEX_ROLE_TO_FILE = {
    "dr_plan": "codex_adapter_templates/codex/agents/dr-plan.toml",
    "dr_pm": "codex_adapter_templates/codex/agents/dr-pm.toml",
    "dr_searcher": "codex_adapter_templates/codex/agents/dr-searcher.toml",
    "dr_analyst": "codex_adapter_templates/codex/agents/dr-analyst.toml",
    "dr_verifier": "codex_adapter_templates/codex/agents/dr-verifier.toml",
    "dr_chief_editor": "codex_adapter_templates/codex/agents/dr-chief-editor.toml",
    "dr_editor_in_chief": "codex_adapter_templates/codex/agents/dr-editor-in-chief.toml",
    "dr_reporter": "codex_adapter_templates/codex/agents/dr-reporter.toml",
}


def replace_opencode_model(path: Path, model: str) -> bool:
    text = path.read_text(encoding="utf-8")
    new_text, count = re.subn(r"(?m)^model:\s*.+$", f"model: {model}", text, count=1)
    if count == 0:
        raise SystemExit(f"failed to locate model field: {path}")
    if new_text == text:
        return False
    path.write_text(new_text, encoding="utf-8")
    return True


def replace_codex_model(path: Path, model: str) -> bool:
    text = path.read_text(encoding="utf-8")
    new_text, count = re.subn(r'(?m)^model\s*=\s*"[^"]+"$', f'model = "{model}"', text, count=1)
    if count == 0:
        raise SystemExit(f"failed to locate model field: {path}")
    if new_text == text:
        return False
    path.write_text(new_text, encoding="utf-8")
    return True


def main() -> int:
    parser = argparse.ArgumentParser(description="Apply model profile to agent files")
    parser.add_argument("--profile", required=True, help="Profile name from configs/models.yaml")
    parser.add_argument("--target", choices=["opencode", "codex", "both"], default="both")
    parser.add_argument(
        "--model-override",
        action="append",
        default=[],
        metavar="ROLE=MODEL",
        help="Override one role model, repeatable",
    )
    parser.add_argument("--dry-run", action="store_true")
    args = parser.parse_args()

    try:
        resolved = resolve_model_profile(
            profile=args.profile,
            overrides=parse_model_overrides(args.model_override),
        )
    except ModelConfigError as exc:
        raise SystemExit(f"model profile resolution failed: {exc}") from exc

    roles = resolved["roles"]
    changed: list[str] = []

    def apply_map(mapping: dict[str, str], mode: str) -> None:
        for role, rel_path in mapping.items():
            model = roles.get(role)
            if not model:
                continue
            file_path = REPO_ROOT / rel_path
            if not file_path.exists():
                continue
            if args.dry_run:
                changed.append(f"{mode}:{rel_path} -> {model}")
                continue
            did_change = replace_opencode_model(file_path, model) if mode == "opencode" else replace_codex_model(file_path, model)
            if did_change:
                changed.append(f"{mode}:{rel_path} -> {model}")

    if args.target in ("opencode", "both"):
        apply_map(OPENCODE_ROLE_TO_FILE, "opencode")
    if args.target in ("codex", "both"):
        apply_map(CODEX_ROLE_TO_FILE, "codex")

    print(f"Profile applied: {resolved['profile']}")
    print(f"Target: {args.target}")
    if changed:
        print("Updated:")
        for item in changed:
            print(f"  - {item}")
    else:
        print("No files changed.")
    return 0


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