"""TaskFlow 状态机与 payload 校验。"""

from __future__ import annotations

import json
from typing import List, Tuple

import pytest

from linksoul_agentsdk.active import (
    FlowEndCallback,
    FlowInterruptCallback,
    FlowStartCallback,
    FlowTaskCallback,
    TaskFlowRequest,
)
from linksoul_agentsdk.enums import FlowMode

from .conftest import FakeLinkskyClient


class _StartRec(FlowStartCallback):
    def __init__(self):
        super().__init__()
        self.events: List[Tuple[str, str, int, str]] = []

    def on_start_request_ack(self, flow_id, event_id, code, msg):
        self.events.append(("req", flow_id, code, msg))

    def on_start_execute_ack(self, flow_id, event_id, code, msg):
        self.events.append(("exec", flow_id, code, msg))


class _TaskRec(FlowTaskCallback):
    def __init__(self):
        super().__init__()
        self.events: List[Tuple[str, int, str]] = []

    def on_task_request_ack(self, flow_id, event_id, code, msg):
        self.events.append(("req", code, msg))

    def on_task_execute_ack(self, flow_id, event_id, code, msg):
        self.events.append(("exec", code, msg))


class _EndRec(FlowEndCallback):
    def __init__(self):
        super().__init__()
        self.events: List[Tuple[int, str]] = []

    def on_end_request_ack(self, flow_id, event_id, code, msg):
        self.events.append((code, msg))


class _InterruptRec(FlowInterruptCallback):
    def __init__(self):
        super().__init__()
        self.events: List[Tuple[int, str]] = []

    def on_interrupt_request_ack(self, flow_id, event_id, code, msg):
        self.events.append((code, msg))


def _flow_with_client(initialized_sdk):
    client = initialized_sdk.linksky_client
    flow = TaskFlowRequest(initialized_sdk, "AGENT_1", "flow_1")
    initialized_sdk.register_task_flow(flow)
    return flow, client


def test_start_request_complex_with_valid_payload(initialized_sdk):
    flow, client = _flow_with_client(initialized_sdk)
    rec = _StartRec()
    event_id = flow.start_request("[{}]", rec, 2000)
    assert event_id.startswith("event_")
    sent = client.find("agentsdk.flow_start.request")
    assert len(sent) == 1
    body = sent[0]["json"]
    assert body["flowId"] == "flow_1"
    assert body["mode"] == "complex"
    assert body["payload"] == [{}]
    assert body["agentMode"] == "active"
    assert rec.timeout == 2000


def test_start_request_simple_requires_payload(initialized_sdk):
    flow = TaskFlowRequest(initialized_sdk, "AGENT_1", "flow_1", FlowMode.SIMPLE)
    initialized_sdk.register_task_flow(flow)
    rec = _StartRec()
    event_id = flow.start_request("", rec, 100)
    # 没有发出去任何 wire 消息，但回调被立即触发为失败
    assert initialized_sdk.linksky_client.find("agentsdk.flow_start.request") == []
    assert rec.events == [("req", "flow_1", 1000, "Agentsdk connection is closed")]


def test_start_request_rejects_bad_json(initialized_sdk):
    flow, client = _flow_with_client(initialized_sdk)
    rec = _StartRec()
    flow.start_request("not-json", rec, 100)
    assert client.find("agentsdk.flow_start.request") == []
    assert rec.events[0][:1] == ("req",)
    _, _, code, msg = rec.events[0]
    assert code == 1001 and "payload" in msg


def test_task_request_emits_event_with_payload(initialized_sdk):
    flow, client = _flow_with_client(initialized_sdk)
    rec = _TaskRec()
    flow.start_request("[{}]", _StartRec(), 100)
    client.reset()
    flow.task_request("[{\"action\":\"x\"}]", rec, 200)
    body = client.sent[0]["json"]
    assert body["type"] == "agentsdk.flow_task.request"
    assert body["payload"] == [{"action": "x"}]
    assert rec.timeout == 200


def test_end_request_emits(initialized_sdk):
    flow, client = _flow_with_client(initialized_sdk)
    rec = _EndRec()
    flow.end_request(rec, 100)
    body = client.sent[-1]["json"]
    assert body["type"] == "agentsdk.flow_end.request"


def test_interrupt_request_emits(initialized_sdk):
    flow, client = _flow_with_client(initialized_sdk)
    rec = _InterruptRec()
    flow.interrupt_request(rec, 100)
    body = client.sent[-1]["json"]
    assert body["type"] == "agentsdk.flow_interrupt.request"


def test_request_when_client_closed_invokes_failure_cb(initialized_sdk):
    flow, client = _flow_with_client(initialized_sdk)
    client.stop()  # 模拟连接断开
    rec = _StartRec()
    flow.start_request("[{}]", rec, 100)
    assert client.find("agentsdk.flow_start.request") == []
    assert rec.events == [("req", "flow_1", 1000, "Agentsdk connection is closed")]


def test_task_callback_lookup_and_cleanup(initialized_sdk):
    flow, client = _flow_with_client(initialized_sdk)
    rec = _TaskRec()
    event_id = flow.task_request("[{}]", rec, 100)
    assert flow.get_task_callback(event_id) is rec
    flow.remove_task_callback(event_id)
    assert flow.get_task_callback(event_id) is None


def test_min_timeout_clamp(initialized_sdk):
    flow, _client = _flow_with_client(initialized_sdk)
    rec = _StartRec()
    flow.start_request("[{}]", rec, 10)  # 小于 50 ms
    assert rec.timeout == 50
