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

use tempfile::TempDir;
use temperlux::settings::{DisplaySettings, Settings, SyncMode};

#[test]
fn save_and_load_roundtrip() {
    let dir = TempDir::new().unwrap();
    let path = dir.path().join("settings.json");

    let mut settings = Settings::default();
    settings.proportional_sync = true;
    settings.set_custom_name("ddc:0", "Left Monitor");
    settings.save_to(&path).unwrap();

    let loaded = Settings::load_from(&path).unwrap();
    assert!(loaded.proportional_sync);
    assert_eq!(loaded.get_custom_name("ddc:0"), Some("Left Monitor".to_string()));
}

#[test]
fn load_missing_file_returns_default() {
    let dir = TempDir::new().unwrap();
    let path = dir.path().join("nonexistent.json");

    let settings = Settings::load_from(&path).unwrap();
    assert!(!settings.proportional_sync);
    assert!(settings.displays.is_empty());
}

#[test]
fn custom_name_not_set_returns_none() {
    let settings = Settings::default();
    assert!(settings.get_custom_name("ddc:0").is_none());
}

#[test]
fn set_custom_name_overwrites() {
    let mut settings = Settings::default();
    settings.set_custom_name("ddc:0", "First");
    settings.set_custom_name("ddc:0", "Second");
    assert_eq!(settings.get_custom_name("ddc:0"), Some("Second".to_string()));
}

#[test]
fn multiple_displays_independent() {
    let mut settings = Settings::default();
    settings.set_custom_name("ddc:0", "Left");
    settings.set_custom_name("ddc:1", "Right");
    assert_eq!(settings.get_custom_name("ddc:0"), Some("Left".to_string()));
    assert_eq!(settings.get_custom_name("ddc:1"), Some("Right".to_string()));
}

#[test]
fn display_settings_default() {
    let ds = DisplaySettings::default();
    assert_eq!(ds.min_brightness, 0.0);
    assert_eq!(ds.max_brightness, 100.0);
    assert!(ds.custom_name.is_none());
}

#[test]
fn get_display_returns_default_for_missing() {
    let settings = Settings::default();
    let ds = settings.get_display("ddc:99");
    assert_eq!(ds.min_brightness, 0.0);
    assert_eq!(ds.max_brightness, 100.0);
}

#[test]
fn set_and_get_display() {
    let mut settings = Settings::default();
    settings.set_display("ddc:1", DisplaySettings {
        min_brightness: 20.0,
        max_brightness: 80.0,
        custom_name: Some("My Monitor".to_string()),
    });
    let ds = settings.get_display("ddc:1");
    assert_eq!(ds.min_brightness, 20.0);
    assert_eq!(ds.max_brightness, 80.0);
    assert_eq!(ds.custom_name, Some("My Monitor".to_string()));
}

#[test]
fn set_display_preserves_other_displays() {
    let mut settings = Settings::default();
    settings.set_display("ddc:1", DisplaySettings {
        min_brightness: 10.0, max_brightness: 90.0, custom_name: None,
    });
    settings.set_display("ddc:2", DisplaySettings {
        min_brightness: 20.0, max_brightness: 80.0, custom_name: Some("Right".to_string()),
    });
    assert_eq!(settings.get_display("ddc:1").min_brightness, 10.0);
    assert_eq!(settings.get_display("ddc:2").custom_name, Some("Right".to_string()));
}

#[test]
fn sync_mode_default_is_off() {
    let settings = Settings::default();
    assert_eq!(settings.sync_mode, SyncMode::Off);
}

#[test]
fn sync_mode_serializes_roundtrip() {
    let dir = TempDir::new().unwrap();
    let path = dir.path().join("settings.json");

    let mut settings = Settings::default();
    settings.sync_mode = SyncMode::Proportional;
    settings.save_to(&path).unwrap();

    let loaded = Settings::load_from(&path).unwrap();
    assert_eq!(loaded.sync_mode, SyncMode::Proportional);
}

#[test]
fn display_order_persists() {
    let dir = TempDir::new().unwrap();
    let path = dir.path().join("settings.json");

    let mut settings = Settings::default();
    settings.display_order = vec!["ddc:2".to_string(), "ddc:1".to_string()];
    settings.save_to(&path).unwrap();

    let loaded = Settings::load_from(&path).unwrap();
    assert_eq!(loaded.display_order, vec!["ddc:2", "ddc:1"]);
}

#[test]
fn show_display_numbers_default_true() {
    let settings = Settings::default();
    assert!(settings.show_display_numbers);
}

#[test]
fn load_invalid_json_returns_error() {
    let dir = TempDir::new().unwrap();
    let path = dir.path().join("settings.json");
    std::fs::write(&path, "{invalid json").unwrap();

    let result = Settings::load_from(&path);
    assert!(result.is_err());
}

#[test]
fn save_creates_parent_directories() {
    let dir = TempDir::new().unwrap();
    let path = dir.path().join("nested").join("dir").join("settings.json");

    let settings = Settings::default();
    settings.save_to(&path).unwrap();
    assert!(path.exists());
}

#[test]
fn latitude_longitude_default() {
    let s = Settings::default();
    assert!((s.latitude - 41.88).abs() < f64::EPSILON);
    assert!((s.longitude - (-87.63)).abs() < f64::EPSILON);
}

#[test]
fn latitude_longitude_persists() {
    let dir = TempDir::new().unwrap();
    let path = dir.path().join("settings.json");
    let mut s = Settings::default();
    s.latitude = 34.05; // LA
    s.longitude = -118.24;
    s.save_to(&path).unwrap();
    let loaded = Settings::load_from(&path).unwrap();
    assert!((loaded.latitude - 34.05).abs() < 0.01);
    assert!((loaded.longitude - (-118.24)).abs() < 0.01);
}

