use crate::rect;

use sdl2::{rect::Rect, render::Canvas, video::Window};

#[derive(Debug, Clone)]
pub struct Container {
    pub start: (i32, i32),
    pub width: u32,
    pub height: u32,
}

pub enum Size {
    Max,
    Absolute(u32),
}

#[derive(Debug, Copy, PartialEq, Clone)]
pub enum Offset {
    Top(u32),
    Left(u32),
    Bottom(u32),
    Right(u32),
}

#[derive(Debug, Copy, PartialEq, Clone)]
pub enum HorAlign {
    Left,
    Center,
    Right,
}

#[derive(Debug, Copy, PartialEq, Clone)]
pub enum VertAlign {
    Top,
    Center,
    Bottom,
}

impl Offset {
    fn apply(self, size: u32) -> u32 {
        match self {
            Self::Top(t) => t,
            Self::Left(l) => l,
            Self::Bottom(b) => size - b,
            Self::Right(r) => size - r,
        }
    }
}

impl Container {
    pub fn uninit() -> Self {
        Self {
            start: (0, 0),
            width: 0,
            height: 0,
        }
    }

    pub fn new(start_x: Offset, start_y: Offset, canvas: &Canvas<Window>) -> Self {
        let (winsize_x, winsize_y) = canvas.window().size();
        Self {
            start: (
                start_x.apply(winsize_x) as i32,
                start_y.apply(winsize_y) as i32,
            ),
            width: 0,
            height: 0,
        }
    }

    pub fn width(mut self, size: Size, canvas: &Canvas<Window>) -> Self {
        match size {
            Size::Max => {
                let (winsize_x, _) = canvas.window().size();
                self.width = winsize_x;
            }
            Size::Absolute(x) => {
                self.width = x;
            }
        }
        self
    }

    pub fn height(mut self, size: Size, canvas: &Canvas<Window>) -> Self {
        match size {
            Size::Max => {
                let (_, winsize_y) = canvas.window().size();
                self.height = winsize_y;
            }
            Size::Absolute(y) => {
                self.height = y;
            }
        }
        self
    }

    pub fn place(&self, widget: &mut Container, hor_align: HorAlign, vert_align: VertAlign) {
        let x = self.start.0
            + match hor_align {
                HorAlign::Left => 0,
                HorAlign::Center => ((self.width / 2).saturating_sub(widget.width / 2)) as i32,
                HorAlign::Right => (self.width - widget.width) as i32,
            };
        let y = self.start.1
            + match vert_align {
                VertAlign::Top => 0,
                VertAlign::Center => ((self.height / 2).saturating_sub(widget.height / 2)) as i32,
                VertAlign::Bottom => (self.height - widget.height) as i32,
            };
        widget.start = (x, y);
    }

    pub fn area(&self) -> Rect {
        rect!(self.start.0, self.start.1, self.width, self.height)
    }
}

#[derive(Debug, Copy, Clone)]
pub struct Widget {
    width: u32,
    height: u32,
}

impl Widget {
    pub fn linear_layout(widgets: &[Widget], padding: u32) -> Widget {
        Widget {
            width: widgets.iter().fold(0, |acc, x| acc + x.width + padding),
            height: widgets.iter().map(|x| x.height).max().unwrap_or(0),
        }
    }
}