use nalgebra_glm::{Vec2, Vec4};

use crate::ecs::text::components::{TextAlignment, TextMesh, VerticalAlignment};
use crate::ecs::text::resources::font_engine::FontKind;
use crate::render::wgpu::passes::geometry::UiLayer;

#[derive(Clone)]
pub struct UiTextInstance {
    pub entity: Option<freecs::Entity>,
    pub text: String,
    pub mesh: TextMesh,
    pub position: Vec2,
    pub color: Vec4,
    pub outline_color: Vec4,
    pub outline_width: f32,
    pub font_size: f32,
    pub alignment: TextAlignment,
    pub vertical_alignment: VerticalAlignment,
    pub monospace: bool,
    pub font_kind: FontKind,
    pub wrap_width: Option<f32>,
    pub clip_rect: Option<Rect>,
    pub layer: UiLayer,
    pub z_index: i32,
    pub character_colors: Option<Vec<Option<Vec4>>>,
    pub character_background_colors: Option<Vec<Option<Vec4>>>,
}

#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Rect {
    pub min: Vec2,
    pub max: Vec2,
}

impl Rect {
    pub fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
        Self {
            min: Vec2::new(x, y),
            max: Vec2::new(x + width, y + height),
        }
    }

    pub fn from_min_max(min: Vec2, max: Vec2) -> Self {
        Self { min, max }
    }

    pub fn from_center_size(center: Vec2, size: Vec2) -> Self {
        let half = size * 0.5;
        Self {
            min: center - half,
            max: center + half,
        }
    }

    pub fn x(&self) -> f32 {
        self.min.x
    }

    pub fn y(&self) -> f32 {
        self.min.y
    }

    pub fn width(&self) -> f32 {
        self.max.x - self.min.x
    }

    pub fn height(&self) -> f32 {
        self.max.y - self.min.y
    }

    pub fn size(&self) -> Vec2 {
        Vec2::new(self.width(), self.height())
    }

    pub fn center(&self) -> Vec2 {
        (self.min + self.max) * 0.5
    }

    pub fn contains(&self, point: Vec2) -> bool {
        point.x >= self.min.x
            && point.x <= self.max.x
            && point.y >= self.min.y
            && point.y <= self.max.y
    }

    pub fn expand(&self, amount: f32) -> Self {
        Self {
            min: self.min - Vec2::new(amount, amount),
            max: self.max + Vec2::new(amount, amount),
        }
    }

    pub fn shrink(&self, amount: f32) -> Self {
        self.expand(-amount)
    }

    pub fn translate(&self, offset: Vec2) -> Self {
        Self {
            min: self.min + offset,
            max: self.max + offset,
        }
    }

    pub fn intersect(&self, other: &Rect) -> Option<Rect> {
        let min_x = self.min.x.max(other.min.x);
        let min_y = self.min.y.max(other.min.y);
        let max_x = self.max.x.min(other.max.x);
        let max_y = self.max.y.min(other.max.y);

        if min_x < max_x && min_y < max_y {
            Some(Rect {
                min: Vec2::new(min_x, min_y),
                max: Vec2::new(max_x, max_y),
            })
        } else {
            None
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Default, serde::Serialize, serde::Deserialize)]
pub enum Anchor {
    #[default]
    TopLeft,
    TopCenter,
    TopRight,
    CenterLeft,
    Center,
    CenterRight,
    BottomLeft,
    BottomCenter,
    BottomRight,
}
