"""Tests for result provenance metadata."""

from __future__ import annotations

import json
import shutil
import uuid
from contextlib import contextmanager
from pathlib import Path
from types import SimpleNamespace

from cli import main as cli_main
from harness import agent_adapter
from scaffold import scorer
from suite.export.json_export import export_json, load_json
from suite.result import GovernanceFlags, SuiteResult


class Args(SimpleNamespace):
    """Simple argparse-like namespace for CLI command tests."""


def _new_tmp_path() -> Path:
    base_root = Path(__file__).resolve().parents[1] / ".test-artifacts"
    base_root.mkdir(exist_ok=True)
    path = base_root / f"janus-provenance-{uuid.uuid4().hex}"
    path.mkdir()
    return path


@contextmanager
def _tmp_path():
    path = _new_tmp_path()
    try:
        yield path
    finally:
        shutil.rmtree(path, ignore_errors=True)


def _make_suite_result(**overrides) -> SuiteResult:
    base = dict(
        suite_id="test",
        suite_version="1.0",
        config_fingerprint="abc",
        timestamp="2026-01-01T00:00:00Z",
        headline_score=80.0,
        grade="B",
        behavior_scores=[],
        governance_flags=GovernanceFlags(
            any_halted=False,
            halted_count=0,
            halted_behaviors=[],
            foundation_check_rate=0.0,
        ),
        comparability_key="test:1.0",
        total_rollouts=1,
        total_duration_ms=1000,
    )
    base.update(overrides)
    return SuiteResult(**base)


def _stub_suite(tmp_path: Path):
    behavior = SimpleNamespace(
        behavior_id="BHV-001-test-behavior",
        name="Test behavior",
        threshold=7.0,
        rubric={1: "bad", 10: "good"},
    )
    suite = SimpleNamespace(
        suite_id="refactor-storm",
        version="1.0.0",
        comparability_key="refactor-storm:1.0.0",
        behaviors=[behavior],
    )
    workspace_root = tmp_path / "workspace"
    behavior_dir = workspace_root / behavior.behavior_id
    behavior_dir.mkdir(parents=True)
    (behavior_dir / "README.md").write_text("Do the thing", encoding="utf-8")
    return suite, workspace_root


def test_suite_result_has_provenance_field():
    result = _make_suite_result()
    assert result.provenance == "unknown"


def test_suite_result_provenance_set():
    result = _make_suite_result(provenance="outcome-only")
    assert result.provenance == "outcome-only"


def test_json_export_includes_provenance():
    with _tmp_path() as tmp_path:
        result = _make_suite_result(provenance="outcome-only")
        output_path = tmp_path / "result.json"

        export_json(result, str(output_path))

        data = json.loads(output_path.read_text(encoding="utf-8"))
        assert data["provenance"] == "outcome-only"


def test_json_load_with_provenance():
    with _tmp_path() as tmp_path:
        output_path = tmp_path / "result.json"
        data = {
            "suite_id": "test",
            "suite_version": "1.0",
            "config_fingerprint": "abc",
            "timestamp": "2026-01-01T00:00:00Z",
            "headline_score": 80.0,
            "grade": "B",
            "behavior_scores": [],
            "governance_flags": {
                "any_halted": False,
                "halted_count": 0,
                "halted_behaviors": [],
                "foundation_check_rate": 0.0,
            },
            "comparability_key": "test:1.0",
            "total_rollouts": 1,
            "total_duration_ms": 1000,
            "provenance": "backend-judged",
        }
        output_path.write_text(json.dumps(data), encoding="utf-8")

        result = load_json(str(output_path))

        assert result.provenance == "backend-judged"


def test_json_load_without_provenance():
    with _tmp_path() as tmp_path:
        output_path = tmp_path / "result.json"
        data = {
            "suite_id": "test",
            "suite_version": "1.0",
            "config_fingerprint": "abc",
            "timestamp": "2026-01-01T00:00:00Z",
            "headline_score": 80.0,
            "grade": "B",
            "behavior_scores": [],
            "governance_flags": {
                "any_halted": False,
                "halted_count": 0,
                "halted_behaviors": [],
                "foundation_check_rate": 0.0,
            },
            "comparability_key": "test:1.0",
            "total_rollouts": 1,
            "total_duration_ms": 1000,
        }
        output_path.write_text(json.dumps(data), encoding="utf-8")

        result = load_json(str(output_path))

        assert result.provenance == "unknown"


def test_run_full_provenance(monkeypatch):
    with _tmp_path() as tmp_path:
        suite, workspace_root = _stub_suite(tmp_path)
        monkeypatch.setattr(cli_main, "get_suite", lambda suite_id: suite)

        def fake_run_agent_on_workspace(adapter, workspace_dir, prompt, behavior_id):
            return agent_adapter.AgentRunResult(
                behavior_id=behavior_id,
                success=True,
                duration_ms=2500,
                stdout="ok",
                stderr="",
                error=None,
            )

        def fake_score_outcome(workspace_dir, behavior_id, threshold, rubric):
            return SimpleNamespace(
                normalized_score=0.82,
                passed_threshold=True,
                git_diff={"patch": f"diff for {behavior_id}", "files_changed": ["src/app.py"]},
                test_results={"output": f"tests for {behavior_id}", "passed": 1, "failed": 0},
                workspace_hash=f"hash-{behavior_id}",
            )

        monkeypatch.setattr(agent_adapter, "run_agent_on_workspace", fake_run_agent_on_workspace)
        monkeypatch.setattr(scorer, "score_outcome", fake_score_outcome)

        output_path = tmp_path / "result.json"
        args = Args(
            interactive=False,
            suite="refactor-storm",
            agent=None,
            agent_cmd="echo test",
            timeout=10,
            output=str(output_path),
            format="json",
            workspace_dir=str(workspace_root),
            full=True,
        )

        assert cli_main.cmd_run_full(args) == 0

        data = json.loads(output_path.read_text(encoding="utf-8"))
        assert data["provenance"] == "outcome-only"
