"""Tests for vmcluster_mcp.models — data contract validation."""

from vmcluster_mcp.models import (
    ClusterHandle,
    ClusterStatus,
    DmesgLine,
    DmesgResult,
    ErrorDetail,
    ExecAllResult,
    ExecResult,
    NetFaultHandle,
    NodeDescriptor,
    NodeStatus,
    SnapshotInfo,
    SnapshotNodeInfo,
    ToolResult,
)


class TestToolResult:
    def test_success_with_string(self):
        r = ToolResult[str](success=True, result="ok", error=None)
        assert r.success is True
        assert r.result == "ok"
        assert r.error is None

    def test_success_with_cluster_status(self):
        ns = NodeStatus(
            name="node-0",
            role="worker",
            ip="192.168.1.10",
            domain_state="running",
            ssh_reachable=True,
        )
        cs = ClusterStatus(cluster_name="test", network_active=True, nodes=[ns])
        r = ToolResult[ClusterStatus](success=True, result=cs)
        assert r.success is True
        assert r.result.cluster_name == "test"
        assert len(r.result.nodes) == 1

    def test_failure_with_error_detail(self):
        err = ErrorDetail(code="SSH_UNREACHABLE", message="Connection refused", node="worker-0")
        r = ToolResult[str](success=False, error=err)
        assert r.success is False
        assert r.result is None
        assert r.error.code == "SSH_UNREACHABLE"
        assert r.error.node == "worker-0"
        assert r.error.recoverable is False

    def test_serialization_round_trip(self):
        r = ToolResult[str](success=True, result="hello")
        d = r.model_dump()
        assert d["success"] is True
        assert d["result"] == "hello"
        assert d["error"] is None
        r2 = ToolResult[str].model_validate(d)
        assert r2.success is True
        assert r2.result == "hello"


class TestErrorDetail:
    def test_defaults(self):
        e = ErrorDetail(code="INTERNAL_ERROR", message="something broke")
        assert e.node is None
        assert e.recoverable is False

    def test_with_node(self):
        e = ErrorDetail(code="SNAPSHOT_NOT_FOUND", message="not found", node="ctrl-0", recoverable=True)
        assert e.node == "ctrl-0"
        assert e.recoverable is True


class TestNodeDescriptor:
    def test_defaults(self):
        nd = NodeDescriptor(name="n1", role="worker", ip="10.0.0.1", ssh_key_path="/key")
        assert nd.ssh_port == 22
        assert nd.ssh_user == "root"


class TestNodeStatus:
    def test_all_domain_states(self):
        for state in ("running", "shut off", "paused", "crashed", "unknown"):
            ns = NodeStatus(name="n", role="w", ip="1.2.3.4", domain_state=state, ssh_reachable=False)
            assert ns.domain_state == state

    def test_optional_fields(self):
        ns = NodeStatus(name="n", role="w", ip="1.2.3.4", domain_state="running", ssh_reachable=True)
        assert ns.artifact_id_installed is None
        assert ns.loaded_modules == []


class TestExecResult:
    def test_fields(self):
        er = ExecResult(exit_code=0, stdout="ok", stderr="", duration_s=1.5, timed_out=False)
        assert er.exit_code == 0
        assert er.timed_out is False


class TestExecAllResult:
    def test_fields(self):
        inner = ExecResult(exit_code=0, stdout="", stderr="", duration_s=0.1, timed_out=False)
        r = ExecAllResult(results={"n1": inner}, all_succeeded=True, failed_nodes=[])
        assert r.all_succeeded is True
        assert "n1" in r.results


class TestClusterHandle:
    def test_round_trip(self):
        nd = NodeDescriptor(name="n1", role="worker", ip="10.0.0.1", ssh_key_path="/key")
        ch = ClusterHandle(cluster_name="test", nodes=[nd], artifact_path="/opt/art", kernel_version="6.8.0")
        d = ch.model_dump()
        ch2 = ClusterHandle.model_validate(d)
        assert ch2.cluster_name == "test"
        assert ch2.nodes[0].name == "n1"


class TestDmesgModels:
    def test_dmesg_line(self):
        dl = DmesgLine(
            timestamp=1234.56, level="warning", facility="kern", text="test msg", classified_as="warn"
        )
        assert dl.level == "warning"
        assert dl.classified_as == "warn"

    def test_dmesg_result(self):
        dr = DmesgResult(lines=[], oops_detected=False, panic_detected=False, warning_count=0, error_count=0)
        assert dr.oops_detected is False


class TestNetFaultHandle:
    def test_fields(self):
        nf = NetFaultHandle(
            handle_id="abc123", fault_type="partition", affected_nodes=["n1", "n2"], created_at="2026-01-01T00:00:00Z"
        )
        assert nf.fault_type == "partition"
        assert len(nf.affected_nodes) == 2


class TestSnapshotInfo:
    def test_round_trip(self):
        sni = SnapshotNodeInfo(node_name="n1", disk_path="/snap/n1.qcow2", size_bytes=1024)
        si = SnapshotInfo(
            snapshot_name="clean", cluster_name="test", created_at="2026-01-01T00:00:00Z", per_node={"n1": sni}
        )
        d = si.model_dump()
        si2 = SnapshotInfo.model_validate(d)
        assert si2.per_node["n1"].size_bytes == 1024
