//! Game capture source configuration using libobs-simple.
//!
//! This module provides capture sources for recording game footage,
//! including game capture, window capture, and monitor capture.

use serde::{Deserialize, Serialize};

/// Game capture source for recording game footage.
///
/// Uses OBS game capture for efficient GPU-based capture.
#[derive(Debug, Clone)]
pub struct GameCapture {
    /// Source name.
    pub name: String,
    /// Window title to capture (if specific window).
    pub window: Option<String>,
    /// Process name to capture.
    pub process_name: Option<String>,
    /// Capture mode.
    pub mode: CaptureMode,
    /// Whether to capture cursor.
    pub capture_cursor: bool,
    /// Window class (Windows only).
    pub window_class: Option<String>,
}

impl Default for GameCapture {
    fn default() -> Self {
        Self {
            name: "Game Capture".to_string(),
            window: None,
            process_name: Some("League of Legends.exe".to_string()),
            mode: CaptureMode::Process,
            capture_cursor: false,
            window_class: Some("RiotWindowClass".to_string()),
        }
    }
}

impl GameCapture {
    /// Create a new game capture source.
    pub fn new(name: &str) -> Self {
        Self {
            name: name.to_string(),
            ..Default::default()
        }
    }

    /// Create a game capture configured for League of Legends.
    pub fn for_league_of_legends() -> Self {
        Self {
            name: "League of Legends Capture".to_string(),
            window: Some("League of Legends (TM) Client".to_string()),
            process_name: Some("League of Legends.exe".to_string()),
            mode: CaptureMode::Window,
            capture_cursor: false,
            window_class: Some("RiotWindowClass".to_string()),
        }
    }

    /// Set the window to capture.
    pub fn with_window(mut self, window: &str) -> Self {
        self.window = Some(window.to_string());
        self.mode = CaptureMode::Window;
        self
    }

    /// Set the process name to capture.
    pub fn with_process(mut self, process: &str) -> Self {
        self.process_name = Some(process.to_string());
        self.mode = CaptureMode::Process;
        self
    }

    /// Set the window class (Windows only).
    pub fn with_window_class(mut self, class: &str) -> Self {
        self.window_class = Some(class.to_string());
        self
    }

    /// Set whether to capture the cursor.
    pub fn with_cursor(mut self, capture: bool) -> Self {
        self.capture_cursor = capture;
        self
    }

    /// Get the window string for OBS in the format "Title:Class:Executable".
    pub fn window_string(&self) -> Option<String> {
        match (&self.window, &self.window_class, &self.process_name) {
            (Some(window), Some(class), Some(process)) => {
                Some(format!("{}:{}:{}", window, class, process))
            }
            (Some(window), None, Some(process)) => Some(format!("{}::{}", window, process)),
            (Some(window), Some(class), None) => Some(format!("{}:{}:", window, class)),
            _ => None,
        }
    }
}

/// Capture mode.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[derive(Default)]
pub enum CaptureMode {
    /// Capture any fullscreen application.
    Any,
    /// Capture a specific window.
    Window,
    /// Capture a specific process.
    #[default]
    Process,
}

/// Window capture source (alternative to game capture).
///
/// Uses OBS window capture which works with more applications
/// but may have slightly higher overhead than game capture.
#[derive(Debug, Clone)]
pub struct WindowCapture {
    /// Source name.
    pub name: String,
    /// Window title.
    pub window_title: String,
    /// Window class (X11/Windows).
    pub window_class: Option<String>,
    /// Whether to capture cursor.
    pub capture_cursor: bool,
}

impl WindowCapture {
    /// Create a new window capture source.
    pub fn new(name: &str, window_title: &str) -> Self {
        Self {
            name: name.to_string(),
            window_title: window_title.to_string(),
            window_class: None,
            capture_cursor: false,
        }
    }

    /// Set the window class (for X11/Windows).
    pub fn with_class(mut self, class: &str) -> Self {
        self.window_class = Some(class.to_string());
        self
    }

    /// Set whether to capture the cursor.
    pub fn with_cursor(mut self, capture: bool) -> Self {
        self.capture_cursor = capture;
        self
    }
}

/// Monitor capture source (fallback).
///
/// Captures an entire monitor. Useful as a fallback when
/// game capture or window capture don't work.
#[derive(Debug, Clone)]
pub struct MonitorCapture {
    /// Source name.
    pub name: String,
    /// Monitor index (0-based).
    pub monitor: u32,
    /// Whether to capture cursor.
    pub capture_cursor: bool,
}

impl MonitorCapture {
    /// Create a new monitor capture source.
    pub fn new(name: &str, monitor: u32) -> Self {
        Self {
            name: name.to_string(),
            monitor,
            capture_cursor: false,
        }
    }

    /// Set whether to capture the cursor.
    pub fn with_cursor(mut self, capture: bool) -> Self {
        self.capture_cursor = capture;
        self
    }
}

/// Capture source type.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SourceType {
    /// Game capture source.
    GameCapture,
    /// Window capture source.
    WindowCapture,
    /// Monitor capture source.
    MonitorCapture,
}

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

    #[test]
    fn test_game_capture_creation() {
        let capture = GameCapture::new("Test Capture");
        assert_eq!(capture.name, "Test Capture");
        assert_eq!(capture.mode, CaptureMode::Process);
    }

    #[test]
    fn test_game_capture_with_process() {
        let capture = GameCapture::new("Test").with_process("League of Legends.exe");

        assert_eq!(
            capture.process_name,
            Some("League of Legends.exe".to_string())
        );
        assert_eq!(capture.mode, CaptureMode::Process);
    }

    #[test]
    fn test_league_capture_config() {
        let capture = GameCapture::for_league_of_legends();
        assert_eq!(capture.name, "League of Legends Capture");
        assert_eq!(
            capture.process_name,
            Some("League of Legends.exe".to_string())
        );
        assert_eq!(capture.window_class, Some("RiotWindowClass".to_string()));
    }

    #[test]
    fn test_window_string() {
        let capture = GameCapture::for_league_of_legends();
        let window_str = capture.window_string();
        assert!(window_str.is_some());
        let s = window_str.unwrap();
        assert!(s.contains("League of Legends"));
        assert!(s.contains("RiotWindowClass"));
    }
}
