//! Tests for Event, EventBuilder, and ApiStats.

use super::*;
use crate::model::event_type::EventType;
use chrono::{TimeZone, Utc};

#[test]
fn test_event_builder_basic() {
    let event = EventBuilder::new("machine-1", EventType::SessionStart, "session-123").build();

    assert_eq!(event.machine_id, "machine-1");
    assert_eq!(event.event_type, EventType::SessionStart);
    assert_eq!(event.session_id, "session-123");
    assert!(event.id.is_none());
}

#[test]
fn test_event_builder_impl_into_string() {
    // Test that impl Into<String> works with &str
    let event = EventBuilder::new("machine", EventType::ApiRequest, "session")
        .framework("claude")
        .model("claude-3-opus")
        .build();

    assert_eq!(event.framework, Some("claude".to_string()));
    assert_eq!(event.model, Some("claude-3-opus".to_string()));
}

#[test]
fn test_event_builder_tokens() {
    let event = EventBuilder::new("machine", EventType::ApiRequest, "session")
        .tokens(1000, 500)
        .build();

    assert_eq!(event.tokens_input, Some(1000));
    assert_eq!(event.tokens_output, Some(500));
}

#[test]
fn test_event_builder_cache_tokens() {
    let event = EventBuilder::new("machine", EventType::ApiRequest, "session")
        .cache_tokens(200, 100)
        .build();

    assert_eq!(event.tokens_cache_read, Some(200));
    assert_eq!(event.tokens_cache_write, Some(100));
}

#[test]
fn test_event_builder_tool() {
    let event = EventBuilder::new("machine", EventType::PreToolUse, "session")
        .tool("toolu_123", "Bash")
        .build();

    assert_eq!(event.tool_use_id, Some("toolu_123".to_string()));
    assert_eq!(event.tool_name, Some("Bash".to_string()));
}

#[test]
fn test_event_builder_all_fields() {
    let ts = Utc::now();
    let event = EventBuilder::new("machine", EventType::ApiRequest, "session")
        .framework("claude")
        .model("claude-3-opus")
        .tokens(1000, 500)
        .cache_tokens(200, 100)
        .cost(0.05)
        .duration_ms(1234)
        .timestamp(ts)
        .payload(r#"{"key": "value"}"#)
        .metadata(r#"{"extra": "data"}"#)
        .build();

    assert_eq!(event.framework, Some("claude".to_string()));
    assert_eq!(event.model, Some("claude-3-opus".to_string()));
    assert_eq!(event.tokens_input, Some(1000));
    assert_eq!(event.tokens_output, Some(500));
    assert_eq!(event.tokens_cache_read, Some(200));
    assert_eq!(event.tokens_cache_write, Some(100));
    assert_eq!(event.cost_usd, Some(0.05));
    assert_eq!(event.duration_ms, Some(1234));
    assert_eq!(event.timestamp, ts);
    assert_eq!(event.payload, Some(r#"{"key": "value"}"#.to_string()));
    assert_eq!(event.metadata, Some(r#"{"extra": "data"}"#.to_string()));
}

#[test]
fn test_event_builder_opt_methods_with_some() {
    let event = EventBuilder::new("machine", EventType::PreToolUse, "session")
        .tool_use_id_opt(Some("toolu_123".to_string()))
        .tool_name_opt(Some("Bash".to_string()))
        .spawned_agent_id_opt(Some("agent-456".to_string()))
        .subagent_type_opt(Some("Explore".to_string()))
        .permission_mode_opt(Some("default".to_string()))
        .transcript_path_opt(Some("/path/to/transcript".to_string()))
        .cwd_opt(Some("/projects/test".to_string()))
        .pid_opt(Some(12345))
        .build();

    assert_eq!(event.tool_use_id, Some("toolu_123".to_string()));
    assert_eq!(event.tool_name, Some("Bash".to_string()));
    assert_eq!(event.spawned_agent_id, Some("agent-456".to_string()));
    assert_eq!(event.subagent_type, Some("Explore".to_string()));
    assert_eq!(event.permission_mode, Some("default".to_string()));
    assert_eq!(
        event.transcript_path,
        Some("/path/to/transcript".to_string())
    );
    assert_eq!(event.cwd, Some("/projects/test".to_string()));
    assert_eq!(event.pid, Some(12345));
}

#[test]
fn test_event_builder_opt_methods_with_none() {
    let event = EventBuilder::new("machine", EventType::PreToolUse, "session")
        .tool_use_id_opt(None)
        .tool_name_opt(None)
        .spawned_agent_id_opt(None)
        .subagent_type_opt(None)
        .permission_mode_opt(None)
        .transcript_path_opt(None)
        .cwd_opt(None)
        .pid_opt(None)
        .build();

    assert!(event.tool_use_id.is_none());
    assert!(event.tool_name.is_none());
    assert!(event.spawned_agent_id.is_none());
    assert!(event.subagent_type.is_none());
    assert!(event.permission_mode.is_none());
    assert!(event.transcript_path.is_none());
    assert!(event.cwd.is_none());
    assert!(event.pid.is_none());
}

#[test]
fn test_event_builder_timestamp_opt_none_keeps_current() {
    let event = EventBuilder::new("machine", EventType::SessionStart, "session")
        .timestamp_opt(None)
        .build();

    // timestamp_opt(None) should keep the timestamp set during new()
    // Just verify timestamp is set (it will be close to now)
    assert!(event.timestamp.timestamp() > 0);
}

#[test]
fn test_event_builder_timestamp_opt_some() {
    let ts = Utc.with_ymd_and_hms(2025, 1, 15, 12, 0, 0).unwrap();
    let event = EventBuilder::new("machine", EventType::SessionStart, "session")
        .timestamp_opt(Some(ts))
        .build();

    assert_eq!(event.timestamp, ts);
}

#[test]
fn test_event_builder_api_request_opt_fields() {
    let event = EventBuilder::new("machine", EventType::ApiRequest, "session")
        .tokens_cache_read_opt(Some(500))
        .tokens_cache_write_opt(Some(100))
        .cost_opt(Some(0.03))
        .duration_ms_opt(Some(2000))
        .model_opt(Some("claude-3-sonnet".to_string()))
        .metadata_opt(Some(r#"{"foo": "bar"}"#.to_string()))
        .payload_opt(Some(r#"{"input": "test"}"#.to_string()))
        .build();

    assert_eq!(event.tokens_cache_read, Some(500));
    assert_eq!(event.tokens_cache_write, Some(100));
    assert_eq!(event.cost_usd, Some(0.03));
    assert_eq!(event.duration_ms, Some(2000));
    assert_eq!(event.model, Some("claude-3-sonnet".to_string()));
    assert_eq!(event.metadata, Some(r#"{"foo": "bar"}"#.to_string()));
    assert_eq!(event.payload, Some(r#"{"input": "test"}"#.to_string()));
}

#[test]
fn test_event_builder_payload_opt_preserves_value() {
    let event = EventBuilder::new("machine", EventType::PreToolUse, "session")
        .payload(r#"{"original": true}"#)
        .payload_opt(None) // Should preserve original value
        .build();

    assert_eq!(event.payload, Some(r#"{"original": true}"#.to_string()));
}

#[test]
fn test_event_builder_individual_setters() {
    let event = EventBuilder::new("machine", EventType::PreToolUse, "session")
        .tool_use_id("toolu_abc")
        .tool_name("Read")
        .spawned_agent_id("agent-xyz")
        .subagent_type("Plan")
        .permission_mode("acceptEdits")
        .transcript_path("/tmp/transcript.jsonl")
        .cwd("/workspace")
        .pid(9999)
        .build();

    assert_eq!(event.tool_use_id, Some("toolu_abc".to_string()));
    assert_eq!(event.tool_name, Some("Read".to_string()));
    assert_eq!(event.spawned_agent_id, Some("agent-xyz".to_string()));
    assert_eq!(event.subagent_type, Some("Plan".to_string()));
    assert_eq!(event.permission_mode, Some("acceptEdits".to_string()));
    assert_eq!(
        event.transcript_path,
        Some("/tmp/transcript.jsonl".to_string())
    );
    assert_eq!(event.cwd, Some("/workspace".to_string()));
    assert_eq!(event.pid, Some(9999));
}
