"""
Tests for FlowsClient.

Uses mock to simulate server responses.
"""

import pytest
from unittest.mock import patch

from boring_os import BoringOS
from boring_os.flow_models import FlowResult, FlowDefinition, FlowListResponse


# Sample data
SAMPLE_FLOW_RESULT = {
    "text": "I've reviewed your account and applied a credit.",
    "nodes_executed": [
        {"node": "triage", "agent": "triage_agent", "duration_ms": 1200},
        {"node": "billing", "agent": "billing_agent", "duration_ms": 2500},
    ],
    "total_cost": 0.0471,
    "execution_id": "flow-exec-789",
    "total_duration_ms": 3700,
}

SAMPLE_FLOW_DEFINITION = {
    "name": "billing_resolution_flow",
    "description": "Resolves billing disputes",
    "nodes": [
        {"name": "triage", "agent": "triage_agent", "description": "Initial triage"},
        {"name": "billing", "agent": "billing_agent", "description": "Billing expert"},
    ],
    "edges": [
        {
            "source": "triage", "target": "billing",
            "condition_type": "keyword_match", "condition_value": "billing",
            "operation": "HANDOFF",
        },
    ],
    "status": "active",
    "version": "1",
}

SAMPLE_FLOW_LIST = {"flows": [SAMPLE_FLOW_DEFINITION], "total": 1}


class TestFlowsClientRun:
    """Tests for flows.run()."""

    def test_run_returns_flow_result(self, client):
        """run() returns a parsed FlowResult."""
        with patch.object(client, "_request", return_value=SAMPLE_FLOW_RESULT):
            result = client.flows.run(
                "billing_resolution_flow",
                message="I want a refund",
            )

        assert isinstance(result, FlowResult)
        assert "credit" in result.text
        assert result.node_count == 2
        assert result.total_cost == 0.0471
        assert result.execution_id == "flow-exec-789"

    def test_run_sends_correct_payload(self, client):
        """run() sends flow name and message."""
        with patch.object(client, "_request", return_value=SAMPLE_FLOW_RESULT) as mock:
            client.flows.run("my_flow", message="hello")

        body = mock.call_args[1]["json"]
        assert body["flow"] == "my_flow"
        assert body["message"] == "hello"


class TestFlowsClientList:
    """Tests for flows.list()."""

    def test_list_returns_flow_list(self, client):
        """list() returns a FlowListResponse."""
        with patch.object(client, "_request", return_value=SAMPLE_FLOW_LIST):
            result = client.flows.list()

        assert isinstance(result, FlowListResponse)
        assert result.total == 1
        assert result.flows[0].name == "billing_resolution_flow"


class TestFlowsClientGet:
    """Tests for flows.get()."""

    def test_get_returns_flow_definition(self, client):
        """get() returns a FlowDefinition."""
        with patch.object(client, "_request", return_value=SAMPLE_FLOW_DEFINITION):
            defn = client.flows.get("billing_resolution_flow")

        assert isinstance(defn, FlowDefinition)
        assert defn.name == "billing_resolution_flow"
        assert len(defn.nodes) == 2
        assert defn.edges[0].condition_type == "keyword_match"


class TestFlowsClientRegister:
    """Tests for flows.register()."""

    def test_register_returns_definition(self, client):
        """register() returns the created FlowDefinition."""
        with patch.object(client, "_request", return_value=SAMPLE_FLOW_DEFINITION):
            defn = client.flows.register(SAMPLE_FLOW_DEFINITION)

        assert isinstance(defn, FlowDefinition)
        assert defn.name == "billing_resolution_flow"
