use engine::prelude::{cgmath::*, *};

pub struct CubeCorners(pub [PositionOnly; 8]);

impl CubeCorners {
    pub fn new(offset: Vector3<f32>, extent: Vector3<f32>) -> Self {
        Self([
            // 0 - left bottom front
            PositionOnly::new(vec3(offset.x, offset.y, offset.z)),
            // 1 - right bottom front
            PositionOnly::new(vec3(offset.x + extent.x, offset.y, offset.z)),
            // 2 - right top front
            PositionOnly::new(vec3(offset.x + extent.x, offset.y + extent.y, offset.z)),
            // 3 - left top front
            PositionOnly::new(vec3(offset.x, offset.y + extent.y, offset.z)),
            // 4 - left bottom back
            PositionOnly::new(vec3(offset.x, offset.y, offset.z + extent.z)),
            // 5 - right bottom back
            PositionOnly::new(vec3(offset.x + extent.x, offset.y, offset.z + extent.z)),
            // 6 - right top back
            PositionOnly::new(vec3(
                offset.x + extent.x,
                offset.y + extent.y,
                offset.z + extent.z,
            )),
            // 7 - left top back
            PositionOnly::new(vec3(offset.x, offset.y + extent.y, offset.z + extent.z)),
        ])
    }
}

pub struct Plane([PositionOnly; 4]);

impl Plane {
    pub fn triangulate(self) -> [PositionOnly; 6] {
        [
            self.0[0], self.0[1], self.0[2], self.0[2], self.0[3], self.0[0],
        ]
    }
}

impl<'a> From<(&'a CubeCorners, usize, usize, usize, usize)> for Plane {
    fn from((corners, i1, i2, i3, i4): (&'a CubeCorners, usize, usize, usize, usize)) -> Self {
        Self([corners.0[i1], corners.0[i2], corners.0[i3], corners.0[i4]])
    }
}

pub struct Cube {
    pub left: Plane,
    pub right: Plane,
    pub front: Plane,
    pub back: Plane,
    pub top: Plane,
    pub bottom: Plane,
}

impl Cube {
    pub fn triangulate(self) -> [PositionOnly; 36] {
        [
            self.front.triangulate(),
            self.left.triangulate(),
            self.right.triangulate(),
            self.back.triangulate(),
            self.top.triangulate(),
            self.bottom.triangulate(),
        ]
        .concat()
        .try_into()
        .unwrap()
    }
}

impl From<CubeCorners> for Cube {
    fn from(corners: CubeCorners) -> Self {
        Self {
            left: Plane::from((&corners, 0, 3, 4, 7)),
            right: Plane::from((&corners, 2, 1, 6, 5)),
            front: Plane::from((&corners, 0, 1, 2, 3)),
            back: Plane::from((&corners, 5, 4, 7, 6)),
            top: Plane::from((&corners, 3, 2, 6, 7)),
            bottom: Plane::from((&corners, 5, 4, 0, 1)),
        }
    }
}