use crate::tui::key_code::KeyCode;
use std::collections::HashSet;

#[derive(Debug, Clone, Copy)]
pub struct TerminalSize {
    pub columns: u16,
    pub rows: u16,
}

impl Default for TerminalSize {
    fn default() -> Self {
        Self {
            columns: 80,
            rows: 24,
        }
    }
}

#[derive(Debug, Clone, Default)]
pub struct Keyboard {
    pub pressed: HashSet<KeyCode>,
    pub just_pressed: HashSet<KeyCode>,
    pub just_released: HashSet<KeyCode>,
}

impl Keyboard {
    pub fn clear_frame(&mut self) {
        self.just_pressed.clear();
        self.just_released.clear();
    }

    pub fn is_pressed(&self, key: KeyCode) -> bool {
        self.pressed.contains(&key)
    }

    pub fn is_just_pressed(&self, key: KeyCode) -> bool {
        self.just_pressed.contains(&key)
    }

    pub fn is_just_released(&self, key: KeyCode) -> bool {
        self.just_released.contains(&key)
    }
}

#[derive(Debug, Clone)]
pub struct Timing {
    pub delta_seconds: f64,
    pub elapsed: f64,
    pub frame_count: u64,
    pub target_fps: u32,
}

impl Default for Timing {
    fn default() -> Self {
        Self {
            delta_seconds: 0.0,
            elapsed: 0.0,
            frame_count: 0,
            target_fps: 30,
        }
    }
}

#[derive(Debug, Clone, Copy, Default)]
pub struct Camera {
    pub offset_column: f64,
    pub offset_row: f64,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MouseButton {
    Left,
    Right,
    Middle,
}

#[derive(Debug, Clone, Default)]
pub struct Mouse {
    pub column: u16,
    pub row: u16,
    pub left_pressed: bool,
    pub right_pressed: bool,
    pub middle_pressed: bool,
    pub left_just_pressed: bool,
    pub right_just_pressed: bool,
    pub middle_just_pressed: bool,
    pub left_just_released: bool,
    pub right_just_released: bool,
    pub middle_just_released: bool,
    pub scroll_delta: i16,
}

impl Mouse {
    pub fn clear_frame(&mut self) {
        self.left_just_pressed = false;
        self.right_just_pressed = false;
        self.middle_just_pressed = false;
        self.left_just_released = false;
        self.right_just_released = false;
        self.middle_just_released = false;
        self.scroll_delta = 0;
    }

    pub fn is_pressed(&self, button: MouseButton) -> bool {
        match button {
            MouseButton::Left => self.left_pressed,
            MouseButton::Right => self.right_pressed,
            MouseButton::Middle => self.middle_pressed,
        }
    }

    pub fn is_just_pressed(&self, button: MouseButton) -> bool {
        match button {
            MouseButton::Left => self.left_just_pressed,
            MouseButton::Right => self.right_just_pressed,
            MouseButton::Middle => self.middle_just_pressed,
        }
    }

    pub fn is_just_released(&self, button: MouseButton) -> bool {
        match button {
            MouseButton::Left => self.left_just_released,
            MouseButton::Right => self.right_just_released,
            MouseButton::Middle => self.middle_just_released,
        }
    }
}
