"""Keep Chapter 8 threshold comparisons label-aware and controlled."""

from __future__ import annotations

import importlib.util
import json
import sys
from pathlib import Path
from types import SimpleNamespace

import pytest

from easycat.debug.export import export_debug_bundle
from easycat.runtime import InMemoryRingBuffer, JournalRecordKind
from tests.teaching import _script_runner as script_runner

ROOT = Path(__file__).resolve().parents[2]
CHAPTER = ROOT / "docs" / "teaching" / "08-smart-turn"
SWEEP = CHAPTER / "threshold_sweep.py"


def _load_sweep_module():
    spec = importlib.util.spec_from_file_location("teaching_ch08_threshold_sweep", SWEEP)
    assert spec is not None and spec.loader is not None
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module


def _bundle(tmp_path: Path) -> Path:
    journal = InMemoryRingBuffer(capacity=10)
    for probability in (0.2, 0.35, 0.45, 0.8):
        journal.append(
            kind=JournalRecordKind.EVENT,
            name="smart_turn.classify",
            session_id="chapter-08-threshold",
            data={
                "stage": "turn",
                "probability": probability,
                "prediction": "complete" if probability >= 0.5 else "incomplete",
                "confirmed": probability >= 0.5,
            },
        )
    path = tmp_path / "chapter-08.bundle"
    export_debug_bundle(SimpleNamespace(journal=journal), path)
    return path


def test_unlabeled_sweep_reports_decision_changes_not_false_positives(tmp_path: Path) -> None:
    result = script_runner.run(
        [sys.executable, str(SWEEP), str(_bundle(tmp_path))],
        cwd=ROOT,
        check=True,
        capture_output=True,
        text=True,
    )

    report = json.loads(result.stdout)
    assert report["classification_count"] == 4
    assert report["newly_accepted_count"] == 2
    assert report["labeled_count"] == 0
    assert report["metrics"] is None
    assert [row["sequence"] for row in report["classifications"] if row["newly_accepted"]] == [
        2,
        3,
    ]


def test_labeled_sweep_distinguishes_helpful_acceptance_from_false_positive(
    tmp_path: Path,
) -> None:
    labels = tmp_path / "labels.json"
    labels.write_text(json.dumps({"1": False, "2": False, "3": True, "4": True}))
    result = script_runner.run(
        [sys.executable, str(SWEEP), str(_bundle(tmp_path)), "--labels", str(labels)],
        cwd=ROOT,
        check=True,
        capture_output=True,
        text=True,
    )

    report = json.loads(result.stdout)
    assert report["labeled_count"] == 4
    assert report["metrics"] == {
        "baseline": {
            "false_negative": 1,
            "false_positive": 0,
            "true_negative": 2,
            "true_positive": 1,
        },
        "candidate": {
            "false_negative": 0,
            "false_positive": 1,
            "true_negative": 1,
            "true_positive": 2,
        },
    }


def test_threshold_sweep_matches_runtime_strict_boundary() -> None:
    sweep = _load_sweep_module()
    report = sweep.sweep_records(
        [
            {"sequence": 1, "name": "smart_turn.classify", "data": {"probability": 0.3}},
            {"sequence": 2, "name": "smart_turn.classify", "data": {"probability": 0.5}},
        ],
        baseline=0.5,
        candidate=0.3,
    )

    assert report["classifications"] == [
        {
            "sequence": 1,
            "probability": 0.3,
            "recorded_confirmed": None,
            "baseline_accepts": False,
            "candidate_accepts": False,
            "newly_accepted": False,
            "user_was_done": None,
        },
        {
            "sequence": 2,
            "probability": 0.5,
            "recorded_confirmed": None,
            "baseline_accepts": False,
            "candidate_accepts": True,
            "newly_accepted": True,
            "user_was_done": None,
        },
    ]


@pytest.mark.parametrize(
    ("labels", "message"),
    [
        ({}, "missing sequences [1, 2, 3, 4]"),
        ({"99": True}, "unknown sequences [99]"),
        ({"1": False, "2": False}, "missing sequences [3, 4]"),
    ],
    ids=("empty", "unknown", "partial"),
)
def test_incomplete_or_unknown_labels_are_rejected(
    labels: dict[str, bool],
    message: str,
    tmp_path: Path,
) -> None:
    labels_path = tmp_path / "labels.json"
    labels_path.write_text(json.dumps(labels))

    result = script_runner.run(
        [sys.executable, str(SWEEP), str(_bundle(tmp_path)), "--labels", str(labels_path)],
        cwd=ROOT,
        check=False,
        capture_output=True,
        text=True,
    )

    assert result.returncode == 2
    assert message in result.stderr
    assert result.stdout == ""
