use hmac::{Hmac, Mac};
use serde_json::json;
use sgclaw::pipe::{Action, AgentMessage, BrowserMessage};
use sgclaw::security::sign_command;
use sha2::Sha256;

type HmacSha256 = Hmac<Sha256>;

#[test]
fn browser_submit_task_round_trip_uses_task_wire_format() {
    let raw = r#"{"type":"submit_task","instruction":"打开百度并搜索今日汇率"}"#;
    let message: BrowserMessage = serde_json::from_str(raw).unwrap();

    assert_eq!(
        message,
        BrowserMessage::SubmitTask {
            instruction: "打开百度并搜索今日汇率".to_string(),
        }
    );
    assert_eq!(serde_json::to_string(&message).unwrap(), raw);
}

#[test]
fn agent_task_complete_and_log_entry_serialize_with_expected_tags() {
    let complete_raw = serde_json::to_string(&AgentMessage::TaskComplete {
        success: true,
        summary: "任务执行完成".to_string(),
    })
    .unwrap();
    let log_raw = serde_json::to_string(&AgentMessage::LogEntry {
        level: "info".to_string(),
        message: "click #submit".to_string(),
    })
    .unwrap();

    assert_eq!(
        complete_raw,
        r#"{"type":"task_complete","success":true,"summary":"任务执行完成"}"#
    );
    assert_eq!(
        log_raw,
        r#"{"type":"log_entry","level":"info","message":"click #submit"}"#
    );
}

#[test]
fn sign_command_uses_newline_canonical_string_with_stable_json() {
    let session_key = vec![1, 2, 3, 4, 5, 6, 7, 8];
    let params = json!({
        "z": 9,
        "a": { "b": 2, "a": 1 }
    });
    let canonical = r#"42
click
{"a":{"a":1,"b":2},"z":9}
oa.example.com"#;

    let mut mac = HmacSha256::new_from_slice(&session_key).unwrap();
    mac.update(canonical.as_bytes());
    let expected = hex::encode(mac.finalize().into_bytes());

    let actual = sign_command(&session_key, 42, &Action::Click, &params, "oa.example.com").unwrap();
    assert_eq!(actual, expected);
}

#[test]
fn sign_command_is_order_independent_for_object_params() {
    let session_key = vec![8, 7, 6, 5, 4, 3, 2, 1];
    let params_a = json!({
        "z": 9,
        "a": { "b": 2, "a": 1 }
    });
    let params_b = json!({
        "a": { "a": 1, "b": 2 },
        "z": 9
    });

    let sig_a = sign_command(
        &session_key,
        7,
        &Action::Navigate,
        &params_a,
        "oa.example.com",
    )
    .unwrap();
    let sig_b = sign_command(
        &session_key,
        7,
        &Action::Navigate,
        &params_b,
        "oa.example.com",
    )
    .unwrap();

    assert_eq!(sig_a, sig_b);
}
