// SPDX-License-Identifier: GPL-3.0-or-later
//! Perf module tests.

#[test]
fn init_disabled_when_path_none() {
    // perf uses global state (OnceLock), so we can only test the disabled path
    // since init can only be called once per process
    assert!(!temperlux::perf::is_enabled());
}

#[test]
fn readback_disabled_by_default() {
    assert!(!temperlux::perf::readback_enabled());
}

#[test]
fn now_ms_returns_zero_when_not_initialized() {
    // START is not set since we didn't call init with a path
    assert_eq!(temperlux::perf::now_ms(), 0);
}

#[test]
fn event_serializes_to_json() {
    let ev = temperlux::perf::Event::SliderChanged {
        seq: 1,
        t_ms: 100,
        display_key: "ddc:1".to_string(),
        gtk_value_pct: 75.0,
        raw_value: 192,
    };
    let json = serde_json::to_string(&ev).unwrap();
    assert!(json.contains("\"kind\":\"SliderChanged\""));
    assert!(json.contains("\"display_key\":\"ddc:1\""));
    assert!(json.contains("\"gtk_value_pct\":75.0"));
}

#[test]
fn header_event_serializes() {
    let ev = temperlux::perf::Event::Header {
        version: 1,
        pid: 1234,
        start_unix_ms: 1700000000000,
    };
    let json = serde_json::to_string(&ev).unwrap();
    assert!(json.contains("\"kind\":\"Header\""));
    assert!(json.contains("\"version\":1"));
}

#[test]
fn worker_dequeued_event_serializes() {
    let ev = temperlux::perf::Event::WorkerDequeued {
        seq: 2,
        t_ms: 105,
        display_key: "ddc:0".to_string(),
        raw_value: 128,
        coalesced_count: 3,
    };
    let json = serde_json::to_string(&ev).unwrap();
    assert!(json.contains("\"coalesced_count\":3"));
}

#[test]
fn ddc_dispatched_event_serializes() {
    let ev = temperlux::perf::Event::DdcDispatched {
        seq: 3,
        t_ms: 110,
        parent_seq: 2,
        display_num: 1,
        raw_value: 128,
    };
    let json = serde_json::to_string(&ev).unwrap();
    assert!(json.contains("\"parent_seq\":2"));
}

#[test]
fn ddc_write_end_event_serializes() {
    let ev = temperlux::perf::Event::DdcWriteEnd {
        seq: 4,
        t_ms: 115,
        parent_seq: 3,
        display_num: 1,
        raw: 128,
        duration_us: 5000,
        success: true,
    };
    let json = serde_json::to_string(&ev).unwrap();
    assert!(json.contains("\"success\":true"));
    assert!(json.contains("\"duration_us\":5000"));
}

#[test]
fn ddc_readback_event_serializes() {
    let ev = temperlux::perf::Event::DdcReadback {
        seq: 5,
        t_ms: 120,
        parent_seq: 4,
        display_num: 1,
        expected_raw: 128,
        actual_raw: 128,
        duration_us: 3000,
        matched: true,
    };
    let json = serde_json::to_string(&ev).unwrap();
    assert!(json.contains("\"matched\":true"));
}

#[test]
fn backlight_write_start_end_events_serialize() {
    let start = temperlux::perf::Event::BacklightWriteStart {
        seq: 6,
        t_ms: 200,
        parent_seq: 5,
        name: "amdgpu_bl0".to_string(),
        raw: 150,
    };
    let end = temperlux::perf::Event::BacklightWriteEnd {
        seq: 7,
        t_ms: 205,
        parent_seq: 6,
        name: "amdgpu_bl0".to_string(),
        raw: 150,
        duration_us: 5000,
        success: true,
    };
    assert!(serde_json::to_string(&start).unwrap().contains("BacklightWriteStart"));
    assert!(serde_json::to_string(&end).unwrap().contains("BacklightWriteEnd"));
}

#[test]
fn default_path_contains_temperlux() {
    let path = temperlux::perf::default_path();
    assert!(path.to_string_lossy().contains("temperlux"));
    assert!(path.to_string_lossy().contains("perf-"));
    assert!(path.to_string_lossy().ends_with(".ndjson"));
}

#[test]
fn log_is_noop_when_disabled() {
    // Should not panic or do anything harmful
    temperlux::perf::log(temperlux::perf::Event::SliderChanged {
        seq: 0,
        t_ms: 0,
        display_key: "ddc:0".to_string(),
        gtk_value_pct: 50.0,
        raw_value: 128,
    });
}
