pub mod ui;

mod window {
    pub use super::ui;
}

use std::cell::RefCell;
use std::sync::{Arc};
use std::time::Duration;

use winit::event::{ElementState, WindowEvent};
use winit::keyboard::KeyCode;

use crate::tacmap::TacticalMap;
use crate::{GameState, SystemicApp};
use crate::solar_system::{SolarSystem, SystemId};
use crate::wgpuctx::{RenderPassBuilder, WgpuCtx};
use crate::eguictx::EguiCtx;

use ui::*;

pub struct GameWindow
{
    window: Arc<winit::window::Window>,
    wgpuctx: WgpuCtx,
    eguictx: EguiCtx,

    tactical_map: TacticalMap,

    ui_state: GameWindowUiState
}

impl GameWindow
{
    pub fn new(
        instance: &wgpu::Instance,
        event_loop: &winit::event_loop::ActiveEventLoop)
    -> Result<GameWindow, ()>
    {
        let window_attrs = winit::window::Window::default_attributes()
            .with_title("Systemic 4X")
            .with_inner_size(winit::dpi::LogicalSize::new(640, 480));

        let window = Arc::new(event_loop.create_window(window_attrs).unwrap());

        let wgpuctx = pollster::block_on(WgpuCtx::new(instance, window.clone()));
        let eguictx = EguiCtx::new(&window, &wgpuctx);

        let tacmap = TacticalMap::new(
            &wgpuctx,
            winit::dpi::LogicalPosition::new(0.0, 0.0),
            winit::dpi::LogicalSize::new(1.0, 1.0));

        Ok(Self {
        window: window,
            wgpuctx: wgpuctx,
            eguictx: eguictx,
            tactical_map: tacmap,
            
            ui_state: Default::default()
        })
    }
    
    pub fn update(
        &mut self,
        game_state: &RefCell<GameState>,
        dt: Duration)
    {
        self.tactical_map.update(game_state, &mut self.ui_state, dt);
    }

    pub fn keyboard_input(
        &mut self,
        game_state: &RefCell<GameState>,
        key_code: KeyCode,
        key_state: ElementState)
    {
        self.tactical_map.keyboard_input(game_state, key_code, key_state);
    }

    pub fn render(
        &mut self,
        game_state: &RefCell<GameState>)
    -> Result<(), wgpu::SurfaceError> {
        if !self.wgpuctx.is_ready() {
            return Ok(());
        }

        self.tactical_map.draw(
            &self.wgpuctx,
            game_state,
            self.ui_state.current_system)?;
        
        let mut encoder = self.wgpuctx.create_default_encoder("Systemic window command encoder");
        let view = self.wgpuctx.prepare_surface(&wgpu::TextureViewDescriptor::default())?;
        {
            let mut pass = RenderPassBuilder::new("Systemic window render pass", &view)
                .clear_color(wgpu::Color { r: 1.0, g: 1.0, b: 1.0, a: 1.0 })
                .build(&mut encoder);

            //Draw the tactical map canvas.
            self.tactical_map.present(&mut pass)?;
        }
        {
            self.eguictx.prepare(&self.window);
            self.ui_state = GameWindowUiState::render(&self.ui_state, game_state, &self.eguictx);

            self.eguictx.present(
                &self.window, 
                &self.wgpuctx, 
                &mut encoder, 
                &view);
        }

        self.wgpuctx.submit_encoder(encoder);
        self.wgpuctx.present_surface();
        self.window.request_redraw();

        Ok(())
    }

    pub fn on_event(
        &mut self,
        event: &WindowEvent)
    {
        if self.eguictx.window_event(&self.window, event).consumed {
            return;
        }
    }

    pub fn resize(
        &mut self,
        width: u32,
        height: u32
    ) {
        if width > 0 && height > 0 {
            self.wgpuctx.resize(width, height);
            self.tactical_map.resize(&self.wgpuctx, width, height);
            self.window.request_redraw();
        }
    }

    pub fn size(
        &self)
    -> winit::dpi::PhysicalSize<u32> {
        self.window.inner_size()
    }
}
