#[derive(Debug, Clone, Copy, Default)]
pub struct ViewportRect {
    pub x: f32,
    pub y: f32,
    pub width: f32,
    pub height: f32,
}

impl ViewportRect {
    pub fn contains(&self, screen_pos: crate::ecs::world::Vec2) -> bool {
        screen_pos.x >= self.x
            && screen_pos.x <= self.x + self.width
            && screen_pos.y >= self.y
            && screen_pos.y <= self.y + self.height
    }

    pub fn to_local(&self, screen_pos: crate::ecs::world::Vec2) -> crate::ecs::world::Vec2 {
        crate::ecs::world::Vec2::new(screen_pos.x - self.x, screen_pos.y - self.y)
    }
}

pub const DEFAULT_WINDOW_ICON: &[u8] = include_bytes!("../../../../images/icon.png");

pub struct Window {
    pub handle: Option<std::sync::Arc<winit::window::Window>>,
    pub title: String,
    pub icon_bytes: Option<&'static [u8]>,
    pub log_config: crate::logging::LogConfig,
    pub next_state: Option<crate::state::NextStateBuilder>,
    pub should_exit: bool,
    pub timing: WindowTiming,
    pub cached_viewport_size: Option<(u32, u32)>,
    pub cached_scale_factor: f32,
    /// Multiplier mapping winit pointer coordinates into the backing-buffer space
    /// of `cached_viewport_size`. On the web the canvas backing resolution can use
    /// a capped device-pixel ratio while winit still reports pointer positions at
    /// the raw ratio, so the two diverge; this is `capped / raw` (always 1.0 on
    /// native and whenever the ratio is not capped).
    pub pointer_viewport_scale: f32,
    pub active_viewport_rect: Option<ViewportRect>,
    pub camera_tile_rects: std::collections::HashMap<crate::ecs::world::Entity, ViewportRect>,
    pub force_render_cameras: std::collections::HashSet<crate::ecs::world::Entity>,
    pub camera_tile_render_iteration: u32,
    pub is_focused: bool,
    pub cursor_locked: bool,
    pub applied_min_window_size: Option<(u32, u32)>,
    pub applied_title: Option<String>,
    pub applied_icon_bytes: Option<&'static [u8]>,
}

impl Default for Window {
    fn default() -> Self {
        Self {
            handle: None,
            title: "Nightshade".to_string(),
            icon_bytes: Some(DEFAULT_WINDOW_ICON),
            log_config: crate::logging::LogConfig::default(),
            next_state: None,
            should_exit: false,
            timing: WindowTiming::default(),
            cached_viewport_size: None,
            cached_scale_factor: 1.0,
            pointer_viewport_scale: 1.0,
            active_viewport_rect: None,
            camera_tile_rects: std::collections::HashMap::new(),
            force_render_cameras: std::collections::HashSet::new(),
            camera_tile_render_iteration: 0,
            is_focused: true,
            cursor_locked: false,
            applied_min_window_size: None,
            applied_title: None,
            applied_icon_bytes: None,
        }
    }
}

#[derive(Clone)]
pub struct WindowTiming {
    pub frames_per_second: f32,
    pub delta_time: f32,
    pub raw_delta_time: f32,
    pub time_speed: f32,
    pub last_frame_start_instant: Option<web_time::Instant>,
    pub current_frame_start_instant: Option<web_time::Instant>,
    pub initial_frame_start_instant: Option<web_time::Instant>,
    pub frame_counter: u32,
    pub uptime_milliseconds: u64,
}

impl Default for WindowTiming {
    fn default() -> Self {
        Self {
            frames_per_second: 0.0,
            delta_time: 0.0,
            raw_delta_time: 0.0,
            time_speed: 1.0,
            last_frame_start_instant: None,
            current_frame_start_instant: None,
            initial_frame_start_instant: None,
            frame_counter: 0,
            uptime_milliseconds: 0,
        }
    }
}
