use core::fmt;
use std::fmt::Debug;

use glam::{UVec2, Vec2};

use crate::{
    color::{Color, WHITE},
    handle::Handle,
    types::Rect,
};

impl Debug for Sprite {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let size = self.size();
        f.debug_struct("Sprite").field("size", &size).finish()
    }
}

/// Sprite
#[derive(Clone)]
pub struct Sprite {
    /// texture
    pub texture: Handle,
    /// src rect from left top to right bottom
    pub src: Option<Rect>,
    /// size
    pub size: UVec2,
    /// color
    pub color: Color,
    /// Spacing
    pub spacing: f32,
    /// Padding
    pub padding: f32,
    /// Flip Horizontal
    pub flip_x: bool,
    /// Flip Vertical
    pub flip_y: bool,
    /// Anchor default (0.5, 0.5) is center
    pub anchor: Vec2,
}

impl Sprite {
    /// Build image from texture
    pub fn new(texture: Handle, size: UVec2) -> Self {
        Self {
            texture,
            size,
            src: None,
            color: WHITE,
            spacing: 0.0,
            padding: 0.0,
            flip_x: false,
            flip_y: false,
            anchor: Vec2::splat(0.5),
        }
    }

    pub fn with_anchor(mut self, anchor: Vec2) -> Self {
        self.anchor = anchor;
        self
    }

    pub fn with_tile(mut self, tile: u16, tile_size: Vec2) -> Self {
        let cols =
            ((self.size.x as f32 - self.padding) / (tile_size.x + self.spacing)).ceil() as u32;
        let row = tile as u32 / cols;
        let col = tile as u32 % cols;
        let src_pos = Vec2::new(
            col as f32 * (tile_size.x + self.spacing) + self.padding,
            row as f32 * (tile_size.y + self.spacing) + self.padding,
        );
        let src_size = Vec2::new(tile_size.x, tile_size.y);
        let src = Rect {
            min: src_pos,
            max: src_pos + src_size,
        };
        self.src = Some(src);
        self
    }

    /// Return image size
    pub fn size(&self) -> UVec2 {
        self.size
    }
}
