from __future__ import annotations

import importlib.util
import json
import os
from pathlib import Path
import subprocess
import tempfile
import unittest
from types import SimpleNamespace
from unittest import mock


SCRIPT = Path(__file__).resolve().parents[1] / "scripts" / "run_agent_once.py"
SPEC = importlib.util.spec_from_file_location("run_agent_once", SCRIPT)
assert SPEC and SPEC.loader
MODULE = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(MODULE)
REPOSITORY = Path(__file__).resolve().parents[5]


def catalog_value(executable: str) -> dict:
    target = {
        "agent": "runtime-agent",
        "model": "runtime-model",
        "execution_class": "cloud_model",
        "selfcheck_required": False,
        "runtime": {
            "command": [executable, "{prompt}", "{target_id}"],
            "environment": {"RUN_TARGET": "{target_id}"},
        },
    }
    routes = {"worker": {}, "review": {}}
    for stage in routes:
        for lane in ("local", "cloud"):
            for grade in range(1, 11):
                routes[stage][f"{lane}-G{grade:02d}"] = {
                    "candidates": ["primary"]
                }
    return {"schema_version": "1.0", "targets": {"primary": target}, "routes": routes}


class ExecutionCatalogRunnerTest(unittest.TestCase):
    def test_build_command_only_expands_injected_template(self) -> None:
        target = SimpleNamespace(
            agent="runtime-agent",
            model="runtime-model",
            catalog_id="target-a",
            runtime={"command": ["runner", "--id", "{target_id}", "{prompt}"]},
        )
        with tempfile.TemporaryDirectory() as raw:
            path = Path(raw)
            command = MODULE.build_command(
                target=target,
                prompt="prompt",
                workspace=path,
                session_id="session-id",
                attempt_dir=path,
            )
        self.assertEqual(command, ["runner", "--id", "target-a", "prompt"])

    def test_missing_catalog_is_rejected(self) -> None:
        with tempfile.TemporaryDirectory(dir=REPOSITORY) as raw:
            workspace = Path(raw) / "workspace"
            workspace.mkdir()
            subprocess.run(
                ["git", "init", "-b", "main", str(workspace)],
                check=True,
                stdout=subprocess.DEVNULL,
            )
            with mock.patch.dict(os.environ, {}, clear=False):
                os.environ.pop(MODULE.CATALOG_ENV, None)
                result = MODULE.main(
                    ["--target-id", "primary", "--workspace", str(workspace), "--probe"]
                )
        self.assertEqual(result, 2)

    def test_probe_executes_catalog_target_once_and_records_revision(self) -> None:
        with tempfile.TemporaryDirectory(dir=REPOSITORY) as raw:
            root = Path(raw)
            workspace = root / "workspace"
            binary = root / "bin"
            workspace.mkdir()
            binary.mkdir()
            subprocess.run(
                ["git", "init", "-b", "main", str(workspace)],
                check=True,
                stdout=subprocess.DEVNULL,
            )
            fake = binary / "runtime-runner"
            fake.write_text(
                "#!/bin/sh\nprintf '%s\\n' MILESTONE_AGENT_READY\n",
                encoding="utf-8",
            )
            fake.chmod(0o755)
            catalog = root / "catalog.json"
            catalog.write_text(json.dumps(catalog_value("runtime-runner")), encoding="utf-8")
            result_file = (
                workspace
                / ".git"
                / "epic-work-preparation"
                / "probe-cycle"
                / "result.json"
            )
            with mock.patch.dict(os.environ, {"PATH": f"{binary}:{os.environ['PATH']}"}):
                result = MODULE.main(
                    [
                        "--execution-catalog",
                        str(catalog),
                        "--target-id",
                        "primary",
                        "--workspace",
                        str(workspace),
                        "--probe",
                        "--result-file",
                        str(result_file),
                    ]
                )
            self.assertEqual(result, 0)
            recorded = json.loads(result_file.read_text(encoding="utf-8"))
            self.assertEqual(recorded["status"], "succeeded")
            self.assertEqual(recorded["target_id"], "primary")
            self.assertEqual(recorded["agent"], "runtime-agent")
            self.assertEqual(recorded["model"], "runtime-model")
            self.assertTrue(recorded["catalog"]["revision"])
            locators = list(
                (workspace / ".git" / "epic-work-preparation" / "runs").glob(
                    "*/locator.json"
                )
            )
            self.assertEqual(len(locators), 1)


if __name__ == "__main__":
    unittest.main()
