use sge_api::shapes_2d::draw_custom_shape;

use super::*;

#[derive(Clone, Copy, Debug)]
pub struct BorderStyle {
    pub thickness: f32,
    pub color: Color,
}

impl BorderStyle {
    pub fn none() -> Self {
        Self {
            thickness: 0.0,
            color: Color::TRANSPARENT,
        }
    }
}

impl Default for BorderStyle {
    fn default() -> Self {
        Self::none()
    }
}

#[derive(Debug)]
enum Side {
    Top,
    Bottom,
    Left,
    Right,
}

impl BorderStyle {
    pub fn new(thickness: f32, color: Color) -> Self {
        Self { thickness, color }
    }

    fn draw(&self, a: Vec2, b: Vec2, side: Side) {
        let ((x_a, y_a), (x_b, y_b)) = match side {
            Side::Top => ((1, 1), (-1, 1)),
            Side::Left => ((1, 1), (1, -1)),
            Side::Bottom => ((1, -1), (-1, -1)),
            Side::Right => ((-1, 1), (-1, -1)),
        };

        let mul_a = Vec2::new(x_a as f32, y_a as f32);
        let mul_b = Vec2::new(x_b as f32, y_b as f32);

        let c = a + (self.thickness * mul_a);
        let d = b + (self.thickness * mul_b);

        draw_custom_shape(vec![a, c, d, b], self.color);
    }

    pub const NONE: Self = Self {
        thickness: 0.0,
        color: Color::TRANSPARENT,
    };
}

#[derive(Debug)]
pub struct Border {
    top: BorderStyle,
    bottom: BorderStyle,
    left: BorderStyle,
    right: BorderStyle,

    child: Child,
}

impl Border {
    pub fn tblr(
        top: BorderStyle,
        bottom: BorderStyle,
        left: BorderStyle,
        right: BorderStyle,
        child: Child,
    ) -> UiRef {
        Self {
            top,
            bottom,
            left,
            right,
            child,
        }
        .to_ref()
    }

    pub fn top_bottom(top: BorderStyle, bottom: BorderStyle, child: Child) -> UiRef {
        Self {
            top,
            bottom,
            left: BorderStyle::NONE,
            right: BorderStyle::NONE,
            child,
        }
        .to_ref()
    }

    pub fn left_right(left: BorderStyle, right: BorderStyle, child: Child) -> UiRef {
        Self {
            top: BorderStyle::NONE,
            bottom: BorderStyle::NONE,
            left,
            right,
            child,
        }
        .to_ref()
    }

    pub fn top(style: BorderStyle, child: Child) -> UiRef {
        Self {
            top: style,
            bottom: BorderStyle::NONE,
            left: BorderStyle::NONE,
            right: BorderStyle::NONE,
            child,
        }
        .to_ref()
    }

    pub fn bottom(style: BorderStyle, child: Child) -> UiRef {
        Self {
            top: BorderStyle::NONE,
            bottom: style,
            left: BorderStyle::NONE,
            right: BorderStyle::NONE,
            child,
        }
        .to_ref()
    }

    pub fn left(style: BorderStyle, child: Child) -> UiRef {
        Self {
            top: BorderStyle::NONE,
            bottom: BorderStyle::NONE,
            left: style,
            right: BorderStyle::NONE,
            child,
        }
        .to_ref()
    }

    pub fn right(style: BorderStyle, child: Child) -> UiRef {
        Self {
            top: BorderStyle::NONE,
            bottom: BorderStyle::NONE,
            left: BorderStyle::NONE,
            right: style,
            child,
        }
        .to_ref()
    }

    pub fn all_style(style: BorderStyle, child: Child) -> UiRef {
        Self {
            top: style,
            bottom: style,
            left: style,
            right: style,
            child,
        }
        .to_ref()
    }

    pub fn all(thickness: f32, color: Color, child: Child) -> UiRef {
        let style = BorderStyle { thickness, color };
        Self {
            top: style,
            bottom: style,
            left: style,
            right: style,
            child,
        }
        .to_ref()
    }

    fn extra_size(&self) -> Vec2 {
        Vec2::new(
            self.left.thickness + self.right.thickness,
            self.top.thickness + self.bottom.thickness,
        )
    }

    fn offset(&self) -> Vec2 {
        Vec2::new(self.left.thickness, self.top.thickness)
    }
}

impl UiNode for Border {
    fn preferred_dimensions(&self) -> Vec2 {
        self.child.node.preferred_dimensions() + self.extra_size()
    }

    fn size(&self, area: Area) -> Vec2 {
        self.child.node.size(area)
    }

    fn draw(&self, mut area: Area, state: &UiState) -> Vec2 {
        self.top.draw(area.top_left(), area.top_right(), Side::Top);
        self.top
            .draw(area.top_left(), area.bottom_left(), Side::Left);
        self.bottom
            .draw(area.bottom_left(), area.bottom_right(), Side::Bottom);
        self.right
            .draw(area.top_right(), area.bottom_right(), Side::Right);

        area.size -= self.extra_size();
        area.top_left += self.offset();

        let dimensions = self.child.node.draw(area, state);
        dimensions + self.extra_size()
    }
}
