//! Cross-platform helper for preventing idle sleep while a turn is running.
//!
//! Platform-specific behavior:
//! - macOS: Uses native IOKit power assertions instead of spawning `caffeinate`.
//! - Linux: Spawns `systemd-inhibit` or `gnome-session-inhibit` while active.
//! - Windows: Uses `PowerCreateRequest` + `PowerSetRequest` with
//!   `PowerRequestSystemRequired`.
//! - Other platforms: No-op backend.

#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
mod dummy;
#[cfg(target_os = "linux")]
mod linux_inhibitor;
#[cfg(target_os = "macos")]
mod macos;
#[cfg(target_os = "windows")]
mod windows_inhibitor;

#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
use dummy as imp;
#[cfg(target_os = "linux")]
use linux_inhibitor as imp;
#[cfg(target_os = "macos")]
use macos as imp;
#[cfg(target_os = "windows")]
use windows_inhibitor as imp;

/// Keeps the machine awake while a turn is in progress when enabled.
#[derive(Debug)]
pub struct SleepInhibitor {
    enabled: bool,
    turn_running: bool,
    platform: imp::SleepInhibitor,
}

impl SleepInhibitor {
    pub fn new(enabled: bool) -> Self {
        Self {
            enabled,
            turn_running: false,
            platform: imp::SleepInhibitor::new(),
        }
    }

    /// Update the active turn state; turns sleep prevention on/off as needed.
    pub fn set_turn_running(&mut self, turn_running: bool) {
        self.turn_running = turn_running;
        if !self.enabled {
            self.release();
            return;
        }

        if turn_running {
            self.acquire();
        } else {
            self.release();
        }
    }

    fn acquire(&mut self) {
        self.platform.acquire();
    }

    fn release(&mut self) {
        self.platform.release();
    }

    /// Return the latest turn-running state requested by the caller.
    pub fn is_turn_running(&self) -> bool {
        self.turn_running
    }
}

#[cfg(test)]
mod tests {
    use super::SleepInhibitor;

    #[test]
    fn sleep_inhibitor_toggles_without_panicking() {
        let mut inhibitor = SleepInhibitor::new(/*enabled*/ true);
        inhibitor.set_turn_running(/*turn_running*/ true);
        assert!(inhibitor.is_turn_running());
        inhibitor.set_turn_running(/*turn_running*/ false);
        assert!(!inhibitor.is_turn_running());
    }

    #[test]
    fn sleep_inhibitor_disabled_does_not_panic() {
        let mut inhibitor = SleepInhibitor::new(/*enabled*/ false);
        inhibitor.set_turn_running(/*turn_running*/ true);
        assert!(inhibitor.is_turn_running());
        inhibitor.set_turn_running(/*turn_running*/ false);
        assert!(!inhibitor.is_turn_running());
    }

    #[test]
    fn sleep_inhibitor_multiple_true_calls_are_idempotent() {
        let mut inhibitor = SleepInhibitor::new(/*enabled*/ true);
        inhibitor.set_turn_running(/*turn_running*/ true);
        inhibitor.set_turn_running(/*turn_running*/ true);
        inhibitor.set_turn_running(/*turn_running*/ true);
        inhibitor.set_turn_running(/*turn_running*/ false);
    }

    #[test]
    fn sleep_inhibitor_can_toggle_multiple_times() {
        let mut inhibitor = SleepInhibitor::new(/*enabled*/ true);
        inhibitor.set_turn_running(/*turn_running*/ true);
        inhibitor.set_turn_running(/*turn_running*/ false);
        inhibitor.set_turn_running(/*turn_running*/ true);
        inhibitor.set_turn_running(/*turn_running*/ false);
    }
}
