#![allow(unused_variables, unused_mut)]

mod game;
mod input;
mod render;

use ash::Device;
use ash::Entry;
use ash::Instance;
use ash::vk;
use game::Camera;
use render::SwapchainCtx;
use render::loading_world::Component;
use render::loading_world::WorldComponent;
use render::skybox::Skybox;
use sdl2::{Sdl, video::Window as SdlWindow};

use std::collections::HashMap;

const APP_NAME: &str = "MineClone";

pub trait GameState {}

pub struct Unstarted;

impl GameState for Unstarted {}

pub struct RenderCtx {
    entry: Entry,
    instance: Instance,
    pdev: vk::PhysicalDevice,
    dev: Device,
    surface: vk::SurfaceKHR,
    queue: vk::Queue,
    queue_idx: u32,
    cmd_buf: vk::CommandBuffer,
    host_vis_idx: u32,
    host_invis_idx: u32,
}

pub struct Window {
    width: u32,
    height: u32,
    _sdl: SdlWindow,
}

pub struct RenderAvailable {
    sdl_context: Sdl,
    window: Window,
    ctx: RenderCtx,
}

impl GameState for RenderAvailable {}

pub struct LoadingWorld {
    sdl_context: Sdl,
    window: Window,
    ctx: RenderCtx,

    requested_descriptors: HashMap<vk::DescriptorType, u32>,

    swapchain: SwapchainCtx,
    pass: vk::RenderPass,

    skybox: Skybox,
    components: Vec<Box<dyn WorldComponent>>,
}

impl GameState for LoadingWorld {}

pub struct InWorld {
    sdl_context: Sdl,
    window: Window,
    ctx: RenderCtx,

    skybox: (Skybox, vk::DescriptorSet),
    components: Vec<Component>,

    sem_avail: vk::Semaphore,
    sem_finish: vk::Semaphore,
    fence_flight: vk::Fence,

    swapchain: SwapchainCtx,
    pass: vk::RenderPass,

    camera: Camera,
}

impl GameState for InWorld {}

pub struct Game<S: GameState> {
    state: S,
}

impl Game<Unstarted> {
    pub fn new() -> Self {
        Self { state: Unstarted }
    }
}

fn decode_rif(raw: &[u8]) -> &[u8] {
    &raw[17..]
}

fn main() {
    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let mut window = video_subsystem
        .window(APP_NAME, 1024, 768)
        .vulkan()
        .resizable()
        .build()
        .unwrap();

    let game = Game::new().init_render(sdl_context, window);
    let mut game = game.start_load_world();
    let cube = game.create_cube();
    game.add_component(cube);
    let game = game.start_world();
    let game = game.main_loop();
}
