"""Tests for verbose mode (PipelineTrace)."""

from __future__ import annotations

from arandu.tracing import PipelineTrace


class TestPipelineTrace:
    """Tests for PipelineTrace and PipelineStep."""

    def test_add_step(self):
        trace = PipelineTrace()
        trace.add_step("extraction", {"facts": 3}, 12.5)

        assert len(trace.steps) == 1
        assert trace.steps[0].name == "extraction"
        assert trace.steps[0].duration_ms == 12.5
        assert trace.steps[0].data == {"facts": 3}

    def test_multiple_steps(self):
        trace = PipelineTrace()
        trace.add_step("extraction", {"facts": 3}, 10.0)
        trace.add_step("entity_resolution", {"entities": 2}, 5.0)
        trace.add_step("reconciliation", {"decisions": []}, 8.0)
        trace.add_step("upsert", {"added": 2}, 3.0)

        assert len(trace.steps) == 4
        assert [s.name for s in trace.steps] == [
            "extraction",
            "entity_resolution",
            "reconciliation",
            "upsert",
        ]

    def test_to_dict(self):
        trace = PipelineTrace()
        trace.add_step("extraction", {"count": 5}, 10.0)

        d = trace.to_dict()
        assert "steps" in d
        assert len(d["steps"]) == 1
        assert d["steps"][0]["name"] == "extraction"
        assert d["steps"][0]["duration_ms"] == 10.0
        assert d["steps"][0]["data"] == {"count": 5}

    def test_to_dict_serializes_uuid(self):
        import uuid

        test_id = uuid.uuid4()
        trace = PipelineTrace()
        trace.add_step("upsert", {"fact_id": test_id}, 1.0)

        d = trace.to_dict()
        assert d["steps"][0]["data"]["fact_id"] == str(test_id)

    def test_to_dict_serializes_datetime(self):
        from datetime import UTC, datetime

        now = datetime.now(UTC)
        trace = PipelineTrace()
        trace.add_step("test", {"timestamp": now}, 1.0)

        d = trace.to_dict()
        assert d["steps"][0]["data"]["timestamp"] == now.isoformat()

    def test_start_and_elapsed(self):
        trace = PipelineTrace()
        t0 = trace.start()
        elapsed = trace.elapsed(t0)

        assert isinstance(elapsed, float)
        assert elapsed >= 0.0

    def test_empty_trace(self):
        trace = PipelineTrace()
        assert len(trace.steps) == 0
        assert trace.to_dict() == {"steps": []}


class TestWriteVerboseSteps:
    """Verify that write pipeline step names match the spec."""

    def test_write_pipeline_step_names(self):
        """Write verbose should produce 4 steps with specific names."""
        expected_names = ["extraction", "entity_resolution", "reconciliation", "upsert"]
        trace = PipelineTrace()
        for name in expected_names:
            trace.add_step(name, {}, 0.0)

        assert [s.name for s in trace.steps] == expected_names

    def test_each_step_has_duration(self):
        trace = PipelineTrace()
        trace.add_step("extraction", {}, 10.5)
        trace.add_step("entity_resolution", {}, 5.2)
        trace.add_step("reconciliation", {}, 8.1)
        trace.add_step("upsert", {}, 3.3)

        for step in trace.steps:
            assert isinstance(step.duration_ms, float)
            assert step.duration_ms >= 0.0


class TestRetrieveVerboseSteps:
    """Verify that read pipeline step names match the spec."""

    def test_read_pipeline_step_names(self):
        """Retrieve verbose should produce 5 steps with specific names."""
        expected_names = ["planning", "retrieval", "reranking", "scoring", "compression"]
        trace = PipelineTrace()
        for name in expected_names:
            trace.add_step(name, {}, 0.0)

        assert [s.name for s in trace.steps] == expected_names


class TestPipelineNone:
    """Verify that pipeline is None when verbose is not used."""

    def test_write_result_default_pipeline_none(self):
        from arandu.client import WriteResult

        result = WriteResult()
        assert result.pipeline is None

    def test_retrieve_result_default_pipeline_none(self):
        from arandu.client import RetrieveResult

        result = RetrieveResult()
        assert result.pipeline is None

    def test_write_result_with_pipeline(self):
        from arandu.client import WriteResult

        trace = PipelineTrace()
        trace.add_step("extraction", {}, 10.0)
        result = WriteResult(pipeline=trace)

        assert result.pipeline is not None
        assert len(result.pipeline.steps) == 1

    def test_retrieve_result_with_pipeline(self):
        from arandu.client import RetrieveResult

        trace = PipelineTrace()
        trace.add_step("planning", {}, 5.0)
        result = RetrieveResult(pipeline=trace)

        assert result.pipeline is not None
        assert len(result.pipeline.steps) == 1
