mod linedef;
mod vertex;

use std::{
    fs::File,
    io::{Read, Seek, SeekFrom},
};

use self::linedef::Linedef;

use super::wadfile::WADFile;
use vertex::Vertex;

enum Lumps {
    THINGS = 1,
    LINEDEFS,
    SIDEDEFS,
    VERTEXES,
    SEGS,
    SSECTORS,
    NODES,
    SECTORS,
    REJECT,
    BLOCKMAP,
}

pub struct DoomLevel {
    pub name: String,
    pub vertexes: Vec<Vertex>,
    pub linedefs: Vec<Linedef>,
}

impl DoomLevel {
    pub fn load_level(wad_file: &WADFile, lvl_index: u32) -> Self {
        Self {
            name: wad_file.get_lump_name(lvl_index),
            vertexes: load_vertexes(
                wad_file,
                wad_file.get_lump_offset(lvl_index + Lumps::VERTEXES as u32),
                wad_file.get_lump_size(lvl_index + Lumps::VERTEXES as u32),
            ),
            linedefs: load_linedefs(
                wad_file,
                wad_file.get_lump_offset(lvl_index + Lumps::LINEDEFS as u32),
                wad_file.get_lump_size(lvl_index + Lumps::LINEDEFS as u32),
            ),
        }
    }
}

fn load_vertexes(wad_file: &WADFile, offset: u32, size: u32) -> Vec<Vertex> {
    let num_vertex: u32 = size / 4u32;

    let mut vertex_list: Vec<Vertex> = Vec::with_capacity(num_vertex as usize);

    let mut vertex_data = File::open(&wad_file.wad_path).unwrap();
    vertex_data.seek(SeekFrom::Start(offset as u64)).unwrap();

    for _ in 0..num_vertex {
        let mut x = [0; 2];
        let mut y = [0; 2];

        vertex_data.read(&mut x).unwrap();
        vertex_data.read(&mut y).unwrap();

        vertex_list.push(Vertex {
            x: i16::from_le_bytes(x),
            y: i16::from_le_bytes(y),
        });
    }

    vertex_list
}

fn load_linedefs(wad_file: &WADFile, offset: u32, size: u32) -> Vec<Linedef> {
    let num_linedef: u32 = size / 14u32;

    let mut linedef_list: Vec<Linedef> = Vec::with_capacity(num_linedef as usize);

    let mut linedef_data = File::open(&wad_file.wad_path).unwrap();
    linedef_data.seek(SeekFrom::Start(offset as u64)).unwrap();

    for _ in 0..num_linedef {
        let mut start_vertex = [0; 2];
        let mut end_vertex = [0; 2];
        let mut flags = [0; 2];
        let mut special_type = [0; 2];
        let mut sector_tag = [0; 2];
        let mut front_sidedef = [0; 2];
        let mut back_sidedef = [0; 2];

        linedef_data.read(&mut start_vertex).unwrap();
        linedef_data.read(&mut end_vertex).unwrap();
        linedef_data.read(&mut flags).unwrap();
        linedef_data.read(&mut special_type).unwrap();
        linedef_data.read(&mut sector_tag).unwrap();
        linedef_data.read(&mut front_sidedef).unwrap();
        linedef_data.read(&mut back_sidedef).unwrap();

        linedef_list.push(Linedef {
            start_vertex: i16::from_le_bytes(start_vertex),
            end_vertex: i16::from_le_bytes(end_vertex),
            flags: i16::from_le_bytes(flags),
            special_type: i16::from_le_bytes(special_type),
            sector_tag: i16::from_le_bytes(sector_tag),
            front_sidedef: i16::from_le_bytes(front_sidedef),
            back_sidedef: i16::from_le_bytes(back_sidedef),
        });
    }

    linedef_list
}
