mod common;

use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
use std::time::{SystemTime, UNIX_EPOCH};
use std::fs;

use common::MockTransport;
use serde_json::json;
use sgclaw::compat::browser_script_skill_tool::BrowserScriptSkillTool;
use sgclaw::pipe::{Action, AgentMessage, BrowserMessage, BrowserPipeTool, Timing};
use sgclaw::security::MacPolicy;
use zeroclaw::skills::SkillTool;
use zeroclaw::tools::Tool;

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

#[tokio::test]
async fn browser_script_skill_tool_executes_packaged_script_via_eval() {
    let skill_dir = unique_temp_dir("sgclaw-browser-script-skill");
    let scripts_dir = skill_dir.join("scripts");
    fs::create_dir_all(&scripts_dir).unwrap();
    fs::write(
        scripts_dir.join("extract_hotlist.js"),
        r#"
const topN = Number(args.top_n || 10);
return {
  sheet_name: "知乎热榜",
  rows: [[1, "标题", `${topN}条`]]
};
"#,
    )
    .unwrap();

    let transport = Arc::new(MockTransport::new(vec![BrowserMessage::Response {
        seq: 1,
        success: true,
        data: json!({
            "text": {
                "sheet_name": "知乎热榜",
                "rows": [[1, "标题", "10条"]]
            }
        }),
        aom_snapshot: vec![],
        timing: Timing {
            queue_ms: 1,
            exec_ms: 5,
        },
    }]));
    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 mut args = HashMap::new();
    args.insert("top_n".to_string(), "How many rows to extract".to_string());
    let skill_tool = SkillTool {
        name: "extract_hotlist".to_string(),
        description: "Extract structured hotlist rows".to_string(),
        kind: "browser_script".to_string(),
        command: "scripts/extract_hotlist.js".to_string(),
        args,
    };
    let tool = BrowserScriptSkillTool::new(
        "zhihu-hotlist",
        &skill_tool,
        &skill_dir,
        browser_tool,
    )
    .unwrap();

    let result = tool
        .execute(json!({
            "expected_domain": "https://www.zhihu.com/hot",
            "top_n": "10"
        }))
        .await
        .unwrap();

    let sent = transport.sent_messages();
    assert!(result.success);
    assert_eq!(
        serde_json::from_str::<serde_json::Value>(&result.output).unwrap(),
        json!({
            "sheet_name": "知乎热榜",
            "rows": [[1, "标题", "10条"]]
        })
    );
    assert!(matches!(
        &sent[0],
        AgentMessage::Command {
            action,
            params,
            security,
            ..
        } if action == &Action::Eval
            && security.expected_domain == "www.zhihu.com"
            && params["script"].as_str().unwrap().contains("const args = {\"top_n\":\"10\"};")
            && params["script"].as_str().unwrap().contains("return {")
    ));
}

fn unique_temp_dir(prefix: &str) -> PathBuf {
    let nanos = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_nanos();
    let path = std::env::temp_dir().join(format!("{prefix}-{nanos}"));
    fs::create_dir_all(&path).unwrap();
    path
}
