mod common;

use std::sync::Arc;
use std::time::Duration;

use common::MockTransport;
use sgclaw::agent::runtime::{browser_action_tool_definition, execute_task_with_provider};
use sgclaw::llm::{ChatMessage, LlmError, LlmProvider, ToolDefinition, ToolFunctionCall};
use sgclaw::pipe::{Action, AgentMessage, BrowserMessage, BrowserPipeTool, Timing};
use sgclaw::security::MacPolicy;

struct FakeProvider {
    calls: Vec<ToolFunctionCall>,
}

impl LlmProvider for FakeProvider {
    fn chat(
        &self,
        _messages: &[ChatMessage],
        _tools: &[ToolDefinition],
    ) -> Result<Vec<ToolFunctionCall>, LlmError> {
        Ok(self.calls.clone())
    }
}

fn test_policy() -> MacPolicy {
    MacPolicy::from_json_str(
        r#"{
            "version": "1.0",
            "domains": { "allowed": ["www.baidu.com"] },
            "pipe_actions": {
                "allowed": ["click", "type", "navigate", "getText"],
                "blocked": []
            }
        }"#,
    )
    .unwrap()
}

#[test]
fn browser_action_tool_definition_uses_expected_name() {
    let tool = browser_action_tool_definition();

    assert_eq!(tool.name, "browser_action");
    assert_eq!(tool.parameters["required"][0], "action");
    assert_eq!(tool.parameters["required"][1], "expected_domain");
}

#[test]
fn runtime_executes_provider_tool_calls_and_returns_summary() {
    let transport = Arc::new(MockTransport::new(vec![
        BrowserMessage::Response {
            seq: 1,
            success: true,
            data: serde_json::json!({ "navigated": true }),
            aom_snapshot: vec![],
            timing: Timing {
                queue_ms: 1,
                exec_ms: 10,
            },
        },
        BrowserMessage::Response {
            seq: 2,
            success: true,
            data: serde_json::json!({ "typed": true }),
            aom_snapshot: vec![],
            timing: Timing {
                queue_ms: 1,
                exec_ms: 10,
            },
        },
    ]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));
    let provider = FakeProvider {
        calls: vec![
            ToolFunctionCall {
                id: "call-1".to_string(),
                name: "browser_action".to_string(),
                arguments: serde_json::json!({
                    "action": "navigate",
                    "expected_domain": "www.baidu.com",
                    "url": "https://www.baidu.com"
                }),
            },
            ToolFunctionCall {
                id: "call-2".to_string(),
                name: "browser_action".to_string(),
                arguments: serde_json::json!({
                    "action": "type",
                    "expected_domain": "www.baidu.com",
                    "selector": "#kw",
                    "text": "天气",
                    "clear_first": true
                }),
            },
        ],
    };

    let summary = execute_task_with_provider(
        transport.as_ref(),
        &browser_tool,
        &provider,
        "打开百度搜索天气",
    )
    .unwrap();
    let sent = transport.sent_messages();

    assert_eq!(summary, "已通过 Agent 执行任务: 打开百度搜索天气");
    assert!(matches!(
        &sent[0],
        AgentMessage::LogEntry { level, message }
            if level == "info" && message == "navigate www.baidu.com"
    ));
    assert!(matches!(
        &sent[1],
        AgentMessage::Command { seq, action, .. }
            if *seq == 1 && action == &Action::Navigate
    ));
    assert!(matches!(
        &sent[2],
        AgentMessage::LogEntry { level, message }
            if level == "info" && message == "type www.baidu.com"
    ));
    assert!(matches!(
        &sent[3],
        AgentMessage::Command { seq, action, .. }
            if *seq == 2 && action == &Action::Type
    ));
}
