use gtk::{gdk, glib};

pub fn try_parse_rgba(hex: &str) -> Result<gdk::RGBA, glib::BoolError> {
    let hex = hex.trim();
    if hex.starts_with("rgb") || hex.starts_with('#') {
        gdk::RGBA::parse(hex)
    } else {
        let len = hex.len();
        if len == 3 || len == 6 {
            gdk::RGBA::parse(format!("#{hex}"))
        } else if len == 2 {
            gdk::RGBA::parse(format!("#{hex}{hex}{hex}"))
        } else {
            Err(glib::bool_error!("Invalid color {hex}"))
        }
    }
}

pub fn calc_contrast_level(bg_color: &gdk::RGBA, fg_color: &gdk::RGBA) -> f32 {
    let bg_luminance = get_luminance(bg_color);
    let fg_luminance = get_luminance(fg_color);
    (bg_luminance.max(fg_luminance) + 0.05) / (bg_luminance.min(fg_luminance) + 0.05)
}

fn get_srgb(c: f32) -> f32 {
    if c <= 0.03928 {
        c / 12.92
    } else {
        ((c + 0.055) / 1.055).powf(2.4)
    }
}

pub fn get_luminance(color: &gdk::RGBA) -> f32 {
    let red = get_srgb(color.red());
    let blue = get_srgb(color.blue());
    let green = get_srgb(color.green());
    red * 0.2126 + blue * 0.0722 + green * 0.7152
}

pub fn rgba_to_hex(rgb: &gdk::RGBA) -> String {
    format!(
        "#{}{}{}",
        to_hex(rgb.red() * 255.0),
        to_hex(rgb.green() * 255.0),
        to_hex(rgb.blue() * 255.0)
    )
}

fn to_hex(n: f32) -> String {
    // Borrowed from https://github.com/emgyrz/colorsys.rs
    let s = format!("{:X}", n.round() as u32);
    if s.len() == 1 {
        "0".to_string() + &s
    } else {
        s
    }
}

#[cfg(test)]
mod tests {
    use super::{gdk, try_parse_rgba};

    #[test]
    fn rgba_parse() {
        assert_eq!(try_parse_rgba("000").unwrap(), gdk::RGBA::BLACK);
        assert_eq!(
            try_parse_rgba("e9").unwrap(),
            gdk::RGBA::parse("#e9e9e9").unwrap()
        );
        assert_eq!(try_parse_rgba("ffffff").unwrap(), gdk::RGBA::WHITE);
    }
}
