use gtk4::glib::{self, Enum};
use serde::{Deserialize, Serialize};

pub const DEFAULT_LINE_HEIGHT: f64 = 1.4;
pub const DEFAULT_PARAGRAPH_SPACING: f64 = 1.2;
pub const DEFAULT_FONT_SIZE: i32 = 11;
pub const DEFAULT_SELECTABLE_TEXT: bool = true;

#[derive(Debug, Clone, PartialEq)]
pub struct WidgetConfig {
    pub line_height: f64,
    pub paragraph_spacing: f64,
    pub inline_math_delimiter: Option<String>,
    pub font_size: i32,
    pub font_style: FontStyle,
    pub justification: Justification,
    pub select_text: bool,
}

impl Default for WidgetConfig {
    fn default() -> Self {
        Self {
            line_height: DEFAULT_LINE_HEIGHT,
            paragraph_spacing: DEFAULT_PARAGRAPH_SPACING,
            inline_math_delimiter: None,
            font_size: DEFAULT_FONT_SIZE,
            font_style: FontStyle::SansSerif,
            justification: Justification::Left,
            select_text: DEFAULT_SELECTABLE_TEXT,
        }
    }
}

impl WidgetConfig {
    pub fn pixels_between_line(&self) -> i32 {
        let pt_per_inch = 72.0;
        let px_per_inch = 96.0;
        let px = (self.line_height - 0.8) * self.font_size as f64 * (pt_per_inch / px_per_inch);
        tracing::trace!(px, "pixels between lines");
        f64::abs(px) as i32
    }
}

#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Enum, Serialize, Deserialize)]
#[repr(u32)]
#[enum_type(name = "Html2GtkFontStyle")]
pub enum FontStyle {
    #[default]
    SansSerif,
    Serif,
}

impl FontStyle {
    pub fn as_css_property(&self) -> &'static str {
        match self {
            FontStyle::SansSerif => "Adwaita Sans",
            FontStyle::Serif => "Noto Serif",
        }
    }
}

impl From<u32> for FontStyle {
    fn from(value: u32) -> FontStyle {
        match value {
            1 => Self::SansSerif,
            _ => Self::Serif,
        }
    }
}

impl std::fmt::Display for FontStyle {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Serif => write!(f, "Serif"),
            Self::SansSerif => write!(f, "Sans Serif"),
        }
    }
}

#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Enum, Serialize, Deserialize)]
#[repr(u32)]
#[enum_type(name = "Html2GtkJustification")]
pub enum Justification {
    #[default]
    Left,
    Fill,
}

impl From<u32> for Justification {
    fn from(value: u32) -> Justification {
        match value {
            1 => Self::Fill,
            _ => Self::Left,
        }
    }
}

impl std::fmt::Display for Justification {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Left => write!(f, "Left"),
            Self::Fill => write!(f, "Fill"),
        }
    }
}

impl From<gtk4::Justification> for Justification {
    fn from(value: gtk4::Justification) -> Self {
        match value {
            gtk4::Justification::Fill => Self::Fill,
            _ => Self::Left,
        }
    }
}

impl From<Justification> for gtk4::Justification {
    fn from(value: Justification) -> Self {
        match value {
            Justification::Left => gtk4::Justification::Left,
            Justification::Fill => gtk4::Justification::Fill,
        }
    }
}
