"""Tests for workflow core types."""
import pytest
from logos_adk.workflow.context import (
    BlackboardConflictError,
    PipelineContext,
    PipelineResult,
    PipelineState,
    StepResult,
    WorkflowBlackboard,
)


class TestPipelineContext:
    def test_create(self):
        ctx = PipelineContext(pipeline_id="p1")
        assert ctx.pipeline_id == "p1"
        assert ctx.data == {}
        assert ctx.metadata == {}

    def test_getitem_setitem(self):
        ctx = PipelineContext(pipeline_id="p1")
        ctx["key"] = "value"
        assert ctx["key"] == "value"

    def test_getitem_missing_raises(self):
        ctx = PipelineContext(pipeline_id="p1")
        with pytest.raises(KeyError):
            _ = ctx["missing"]

    def test_get_with_default(self):
        ctx = PipelineContext(pipeline_id="p1")
        assert ctx.get("missing", 42) == 42
        assert ctx.get("missing") is None

    def test_last_output(self):
        ctx = PipelineContext(pipeline_id="p1")
        ctx["_last"] = "hello"
        assert ctx["_last"] == "hello"

    def test_blackboard_uses_versioned_mapping(self):
        ctx = PipelineContext(pipeline_id="p1")
        assert isinstance(ctx.blackboard, WorkflowBlackboard)
        ctx.blackboard["draft"] = "v1"
        assert ctx.blackboard.version("draft") == 1
        ctx.blackboard.compare_and_set("draft", "v2", expected_version=1)
        assert ctx.blackboard["draft"] == "v2"
        assert ctx.blackboard.version("draft") == 2

    def test_blackboard_compare_and_set_conflict_raises(self):
        ctx = PipelineContext(pipeline_id="p1")
        ctx.blackboard["draft"] = "v1"
        with pytest.raises(BlackboardConflictError):
            ctx.blackboard.compare_and_set("draft", "v2", expected_version=0)


class TestStepResult:
    def test_create(self):
        r = StepResult(output="done", status="completed", duration_ms=10.0)
        assert r.output == "done"
        assert r.status == "completed"
        assert r.metadata == {}

    def test_failed(self):
        r = StepResult(output=None, status="failed", duration_ms=5.0, metadata={"error": "boom"})
        assert r.status == "failed"


class TestPipelineResult:
    def test_create(self):
        ctx = PipelineContext(pipeline_id="p1")
        r = PipelineResult(
            status="completed",
            outputs={"s1": StepResult(output="x", status="completed", duration_ms=1.0)},
            context=ctx,
            duration_ms=100.0,
        )
        assert r.status == "completed"
        assert r.outputs["s1"].output == "x"


class TestPipelineState:
    def test_create(self):
        s = PipelineState(
            pipeline_id="p1",
            pipeline_name="test",
            current_step_index=0,
            status="running",
        )
        assert s.pipeline_id == "p1"
        assert s.context_data == {}
        assert s.step_results == {}

    def test_to_agent_state(self):
        from logos_adk.state import AgentState
        s = PipelineState(
            pipeline_id="p1",
            pipeline_name="test",
            current_step_index=2,
            status="paused",
            context_data={"key": "val"},
        )
        agent_state = s.to_agent_state()
        assert isinstance(agent_state, AgentState)
        assert agent_state.session_id == "p1"
        assert "pipeline_state" in agent_state.metadata

    def test_from_agent_state(self):
        s = PipelineState(
            pipeline_id="p1",
            pipeline_name="test",
            current_step_index=2,
            status="paused",
        )
        agent_state = s.to_agent_state()
        restored = PipelineState.from_agent_state(agent_state)
        assert restored.pipeline_id == "p1"
        assert restored.current_step_index == 2
        assert restored.status == "paused"

    def test_persists_blackboard_versions(self):
        state = PipelineState(
            pipeline_id="p1",
            pipeline_name="test",
            current_step_index=1,
            status="paused",
            blackboard_data={"draft": "saved"},
            blackboard_versions_data={"draft": 3},
        )
        restored = PipelineState.from_agent_state(state.to_agent_state())
        assert restored.blackboard_data == {"draft": "saved"}
        assert restored.blackboard_versions_data == {"draft": 3}
