use ab_glyph::{Font, FontVec, PxScale, ScaleFont};

use crate::{error::FontError, font::FontProvider};

pub struct TtfFont {
    font: FontVec,
    /// The height of the text in Minecraft blocks (pixels)
    scale: PxScale,
    /// How "thick" a pixel needs to be to become a block (0.0 to 1.0)
    /// Lower threshold = thicker text, Higher threshold = thinner text
    threshold: f32,
}

impl TtfFont {
    pub fn from_bytes(font_data: &[u8], block_height: f32) -> Result<Self, FontError> {
        let font = FontVec::try_from_vec(font_data.to_vec())
            .map_err(|_| FontError::InvalidTtf)?;

        Ok(Self {
            font,
            scale: PxScale::from(block_height),
            threshold: 0.5, // Default threshold, can be adjusted
        })
    }

    pub fn with_threshold(mut self, threshold: f32) -> Self {
        self.threshold = threshold.clamp(0.0, 0.99);
        self
    }
}

impl FontProvider for TtfFont {
    fn get_glyph(&self, character: char) -> Option<crate::font::Glyph> {
        let scaled_font = self.font.as_scaled(self.scale);
        let glyph_id = scaled_font.glyph_id(character);

        if glyph_id.0 == 0 {
            return None; // Character not found in font
        }

        let q_glyph = glyph_id.with_scale_and_position(self.scale, ab_glyph::point(0.0, 0.0));

        if let Some(outlined) = scaled_font.outline_glyph(q_glyph) {
            let bounds = outlined.px_bounds();

            let width = bounds.width().ceil() as u32;
            let height = bounds.height().ceil() as u32;
            let mut data = vec![false; (width * height) as usize];

            outlined.draw(|x, y, coverage| {
                if coverage >= self.threshold {
                    if x < width && y < height {
                        let idx = (y * width + x) as usize;
                        data[idx] = true;
                    }
                }
            });

            Some(crate::font::Glyph {
                width,
                height,
                data,
            })
        } else {
            if character.is_whitespace() {
                let width = scaled_font.h_advance(glyph_id).ceil() as u32;

                Some(crate::font::Glyph {
                    width,
                    height: self.scale.y as u32,
                    data: vec![false; (width * self.scale.y as u32) as usize],
                })
            } else {
                None
            }
        }
    }

    fn letter_spacing(&self) -> u32 {
        1
    }
}
