"""Tests for MCP root-cause-analysis context resolution and error handling."""

from __future__ import annotations

import pytest

from llmdebug.config import SnapshotConfig
from llmdebug.mcp_rca import (
    RCAInputError,
    SnapshotLoadError,
    extract_evidence_refs,
    resolve_rca_advance_context,
)
from llmdebug.output import write_bundle


def _write_snapshot(out_dir: str) -> None:
    payload = {
        "schema_version": "1.0",
        "name": "test_example",
        "timestamp_utc": "2026-02-07T21:00:00Z",
        "llmdebug_version": "2.0.0",
        "exception": {
            "type": "ValueError",
            "qualified_type": "builtins.ValueError",
            "message": "invalid literal for int(): 'abc'",
        },
        "traceback": "Traceback (most recent call last):\nValueError: invalid literal",
        "frames": [
            {
                "file": "/code/app.py",
                "file_rel": "app.py",
                "line": 42,
                "function": "parse_input",
                "locals": {"value": "'abc'"},
                "locals_meta": {"value": {"type": "builtins.str"}},
            }
        ],
        "crash_frame_index": 0,
        "pytest": {"nodeid": "tests/test_app.py::test_parse"},
    }
    cfg = SnapshotConfig(out_dir=out_dir, output_format="json")
    write_bundle(payload, cfg)


def test_resolve_rca_advance_context_parses_manual_fields_without_snapshot(tmp_path) -> None:
    context = resolve_rca_advance_context(
        out_dir=str(tmp_path),
        snapshot_path="",
        session_id=" sess-1 ",
        failure_signature=" sig-1 ",
        evidence_refs="a,b , c",
        hypothesis=" hypothesis ",
        experiment_plan=" plan ",
        proposed_change_summary=" summary ",
        verification_status="pass",
        verification_checks="pytest, lint ",
        override_reason=" explore ",
    )
    assert context.snapshot is None
    assert context.session_id == "sess-1"
    assert context.failure_signature == "sig-1"
    assert context.evidence_refs == ["a", "b", "c"]
    assert context.hypothesis == "hypothesis"
    assert context.experiment_plan == "plan"
    assert context.proposed_change_summary == "summary"
    assert context.override_reason == "explore"
    assert context.verification_result == {"status": "pass", "checks": ["pytest", "lint"]}


def test_resolve_rca_advance_context_rejects_partial_manual_identity(tmp_path) -> None:
    _write_snapshot(str(tmp_path))
    with pytest.raises(RCAInputError, match="provide both session_id and failure_signature"):
        resolve_rca_advance_context(
            out_dir=str(tmp_path),
            snapshot_path="",
            session_id="manual-session",
            failure_signature="",
            evidence_refs="",
            hypothesis="",
            experiment_plan="",
            proposed_change_summary="",
            verification_status="",
            verification_checks="",
            override_reason="",
        )


def test_resolve_rca_advance_context_derives_identity_when_manual_identity_absent(tmp_path) -> None:
    _write_snapshot(str(tmp_path))
    context = resolve_rca_advance_context(
        out_dir=str(tmp_path),
        snapshot_path="",
        session_id="",
        failure_signature="",
        evidence_refs="",
        hypothesis="",
        experiment_plan="",
        proposed_change_summary="",
        verification_status="",
        verification_checks="",
        override_reason="",
    )
    assert context.snapshot is not None
    assert context.session_id
    assert context.failure_signature.startswith("ValueError:")
    assert context.verification_result is None


def test_resolve_rca_advance_context_raises_snapshot_load_error(tmp_path) -> None:
    missing_path = tmp_path / "missing.json"
    with pytest.raises(SnapshotLoadError, match="Error loading snapshot: FileNotFoundError"):
        resolve_rca_advance_context(
            out_dir=str(tmp_path),
            snapshot_path=str(missing_path),
            session_id="",
            failure_signature="",
            evidence_refs="",
            hypothesis="",
            experiment_plan="",
            proposed_change_summary="",
            verification_status="",
            verification_checks="",
            override_reason="",
        )


def test_extract_evidence_refs_handles_non_numeric_line() -> None:
    refs = extract_evidence_refs(
        {
            "exception": {"type": "ValueError", "message": "boom"},
            "frames": [{"file": "/code/app.py", "line": "?"}],
            "crash_frame_index": 0,
            "pytest": {"nodeid": "tests/test_app.py::test_parse"},
        }
    )

    assert "exception:ValueError" in refs
    assert "crash_frame:/code/app.py:0:?" in refs
    assert "pytest_nodeid:tests/test_app.py::test_parse" in refs
