"""Tests for CLI model regression and metrics subcommands."""

from __future__ import annotations

import json
import sys
from unittest import mock

import pytest

from orxaq.experiences import cli as cli_mod
from orxaq.kernel.checkpoint import CheckpointStore, create_checkpoint
from orxaq.kernel.types import CausalEdge, CausalRole, Entity, VariableType
from orxaq.kernel.world_dag import WorldDAG


def _make_entity(eid: str) -> Entity:
    return Entity(
        entity_id=eid,
        name=eid,
        causal_role=CausalRole.EXOGENOUS,
        variable_type=VariableType.STATIC,
    )


def _make_dag(n: int = 3) -> WorldDAG:
    dag = WorldDAG()
    ids = [f"e{i}" for i in range(n)]
    for eid in ids:
        dag.add_entity(_make_entity(eid))
    for i in range(n - 1):
        dag.add_edge(
            CausalEdge(
                source=ids[i],
                target=ids[i + 1],
                mechanism="test",
                confidence=0.8,
                soliton_score=0.7,
            )
        )
    return dag


@pytest.fixture()
def store_dir(tmp_path):
    """Create checkpoint store with two versions."""
    store = CheckpointStore(tmp_path / "checkpoints")
    dag1 = _make_dag(3)
    cp1 = create_checkpoint(dag1, "test_model", "1.0")
    store.save(cp1)

    dag2 = _make_dag(4)
    cp2 = create_checkpoint(dag2, "test_model", "2.0")
    store.save(cp2)

    return str(tmp_path / "checkpoints")


class TestCLIModelRegression:
    def test_regression_pass(self, store_dir, capsys):
        with mock.patch.object(
            sys,
            "argv",
            [
                "orxaq",
                "model",
                "regression",
                "--name",
                "test_model",
                "--v1",
                "1.0",
                "--v2",
                "1.0",
                "--store",
                store_dir,
            ],
        ):
            rc = cli_mod.main()
        assert rc == 0
        out = capsys.readouterr().out
        assert "PASS" in out

    def test_regression_with_changes(self, store_dir, capsys):
        with mock.patch.object(
            sys,
            "argv",
            [
                "orxaq",
                "model",
                "regression",
                "--name",
                "test_model",
                "--v1",
                "1.0",
                "--v2",
                "2.0",
                "--store",
                store_dir,
            ],
        ):
            cli_mod.main()
        out = capsys.readouterr().out
        assert "Baseline:" in out or "Regression" in out

    def test_regression_json(self, store_dir, capsys):
        with mock.patch.object(
            sys,
            "argv",
            [
                "orxaq",
                "--json",
                "model",
                "regression",
                "--name",
                "test_model",
                "--v1",
                "1.0",
                "--v2",
                "2.0",
                "--store",
                store_dir,
            ],
        ):
            cli_mod.main()
        out = capsys.readouterr().out
        data = json.loads(out)
        assert "passed" in data
        assert "metrics" in data
        assert "structural" in data


class TestCLIModelMetrics:
    def test_metrics_specific_version(self, store_dir, capsys):
        with mock.patch.object(
            sys,
            "argv",
            [
                "orxaq",
                "model",
                "metrics",
                "--name",
                "test_model",
                "--version",
                "1.0",
                "--store",
                store_dir,
            ],
        ):
            rc = cli_mod.main()
        assert rc == 0
        out = capsys.readouterr().out
        assert "entity_count" in out

    def test_metrics_latest(self, store_dir, capsys):
        with mock.patch.object(
            sys,
            "argv",
            [
                "orxaq",
                "model",
                "metrics",
                "--name",
                "test_model",
                "--store",
                store_dir,
            ],
        ):
            rc = cli_mod.main()
        assert rc == 0
        out = capsys.readouterr().out
        assert "Model:" in out

    def test_metrics_json(self, store_dir, capsys):
        with mock.patch.object(
            sys,
            "argv",
            [
                "orxaq",
                "--json",
                "model",
                "metrics",
                "--name",
                "test_model",
                "--version",
                "1.0",
                "--store",
                store_dir,
            ],
        ):
            rc = cli_mod.main()
        assert rc == 0
        data = json.loads(capsys.readouterr().out)
        assert "metrics" in data
        assert data["metrics"]["entity_count"] == 3.0

    def test_metrics_not_found(self, store_dir, capsys):
        with mock.patch.object(
            sys,
            "argv",
            [
                "orxaq",
                "model",
                "metrics",
                "--name",
                "nonexistent",
                "--store",
                store_dir,
            ],
        ):
            rc = cli_mod.main()
        assert rc == 1
