use macroquad::color::{BLACK, Color};
use macroquad::math::Vec2;
use macroquad::prelude::{Font, TextDimensions};
use macroquad::text::{TextParams, draw_text_ex, measure_text};

#[allow(dead_code)]
#[derive(Debug, Clone, Copy, Default)]
pub enum Justified {
    Right,
    Left,
    #[default]
    Center,
    CenterVertical,
    CenterHorizontal,
}

impl Justified {
    pub fn text_offset(&self, text_size: TextDimensions) -> Vec2 {
        match self {
            Justified::Right => Vec2::new(text_size.width, 0.0) * 0.5,
            Justified::Left => Vec2::new(0.0, 0.0),
            Justified::Center => -Vec2::new(text_size.width, text_size.height) * 0.5,
            Justified::CenterVertical => -Vec2::new(0.0, text_size.height) * 0.5,
            Justified::CenterHorizontal => -Vec2::new(text_size.width, 0.0) * 0.5,
        }
    }
}

#[derive(Debug, Default, Clone)]
pub struct TextConfigBuilder<'a> {
    text_config: TextConfig<'a>,
}

#[allow(dead_code)]
impl<'a> TextConfigBuilder<'a> {
    pub fn new(text_config: TextConfig<'a>) -> Self {
        Self { text_config }
    }

    pub fn font(mut self, font: &'a Font) -> Self {
        self.text_config.font = Some(font);
        self
    }

    pub fn font_size(mut self, font_size: u16) -> Self {
        self.text_config.font_size = font_size;
        self
    }

    pub fn font_scale(mut self, font_scale: f32) -> Self {
        self.text_config.font_scale = font_scale;
        self
    }

    pub fn font_scale_aspect(mut self, font_scale_aspect: f32) -> Self {
        self.text_config.font_scale_aspect = font_scale_aspect;
        self
    }

    pub fn rotation(mut self, rotation: f32) -> Self {
        self.text_config.rotation = rotation;
        self
    }

    pub fn color(mut self, color: Color) -> Self {
        self.text_config.color = color;
        self
    }

    pub fn justification(mut self, justification: Justified) -> Self {
        self.text_config.justification = justification;
        self
    }

    pub fn build(self) -> TextConfig<'a> {
        self.text_config
    }
}

#[derive(Debug)]
pub struct TextInfo {
    pub text_dimensions: TextDimensions,
    pub pos: Vec2,
}

#[derive(Debug, Clone)]
pub struct TextConfig<'a> {
    font: Option<&'a Font>,
    font_size: u16,
    font_scale: f32,
    font_scale_aspect: f32,
    rotation: f32,
    color: Color,
    justification: Justified,
}

impl<'a> Default for TextConfig<'a> {
    fn default() -> Self {
        Self {
            font: None,
            font_size: 12,
            font_scale: 1.0,
            font_scale_aspect: 1.0,
            rotation: 0.0,
            color: BLACK,
            justification: Default::default(),
        }
    }
}

impl<'a> TextConfig<'a> {
    pub fn draw_text(&self, text: &str, pos: Vec2) -> TextInfo {
        let text_size = self.measure_text(text);
        let text_params = TextParams {
            font: self.font,
            font_size: self.font_size,
            font_scale: self.font_scale,
            font_scale_aspect: self.font_scale_aspect,
            rotation: self.rotation,
            color: self.color,
        };

        let text_pos = pos + self.justification.text_offset(text_size);

        draw_text_ex(text, text_pos.x, text_pos.y, text_params);

        TextInfo {
            text_dimensions: text_size,
            pos,
        }
    }

    pub fn draw_text_box(&self, text: &str, pos: Vec2, size: Vec2) -> TextInfo {
        let mut lines: Vec<String> = text.split("\n").map(|s| s.to_string()).collect();
        let mut line_pos = pos;

        let mut line_ndx = 0;
        loop {
            if line_ndx >= lines.len() {
                break;
            }

            let line = &lines[line_ndx];
            let line_size = self.measure_text(line);
            let line: Vec<&str> = line.split(" ").collect();

            let mut word_pos = line_pos;

            for word_ndx in 0..line.len() {
                let word = line[word_ndx];
                let word_info = self.draw_text(&format!("{word} "), word_pos);
                word_pos.x += word_info.text_dimensions.width;

                if word_pos.x > size.x {
                    let new_line = format!("\t\t\t{}", line[word_ndx + 1..].join(" "));
                    lines.insert(line_ndx + 1, new_line);
                    break;
                }
            }

            line_ndx += 1;

            line_pos.y += line_size.height * 1.2;

            if line_pos.y > size.y {
                // Stop drawing text
                break;
            }
        }

        TextInfo {
            text_dimensions: TextDimensions {
                width: size.x,
                height: size.y,
                offset_y: 0.0,
            },
            pos,
        }
    }

    pub fn measure_text(&self, text: &str) -> TextDimensions {
        measure_text(text, self.font, self.font_size, self.font_scale)
    }
}

impl<'a> From<TextConfig<'a>> for TextConfigBuilder<'a> {
    fn from(val: TextConfig<'a>) -> Self {
        TextConfigBuilder::new(val)
    }
}
