use std::collections::HashMap;
use std::sync::Mutex;

lazy_static::lazy_static! {
    static ref COLOR_NAMES: HashMap<String, (f32, f32, f32)> = {
        HashMap::from([
            ("black".into(), (0.0, 0.0, 0.0)),
            ("white".into(), (1.0, 1.0, 1.0)),
            ("red".into(), (1.0, 0.0, 0.0)),
            ("green".into(), (0.0, 1.0, 0.0)),
            ("blue".into(), (0.0, 0.0, 1.0)),
            ("yellow".into(), (1.0, 1.0, 0.0)),
            ("cyan".into(), (0.0, 1.0, 1.0)),
            ("magenta".into(), (1.0, 0.0, 1.0)),
            ("gray".into(), (0.5, 0.5, 0.5)),
            ("grey".into(), (0.5, 0.5, 0.5)),
            ("orange".into(), (1.0, 0.647, 0.0)),
            ("purple".into(), (0.5, 0.0, 0.5)),
            ("pink".into(), (1.0, 0.753, 0.796)),
            ("brown".into(), (0.647, 0.165, 0.165)),
            ("navy".into(), (0.0, 0.0, 0.5)),
            ("teal".into(), (0.0, 0.5, 0.5)),
        ])
    };
    static ref COLOR_CACHE: Mutex<HashMap<String, Option<(f32, f32, f32)>>> = Mutex::new(HashMap::new());
}

/// 将 CSS 颜色字符串解析为 PDF RGB 值 (0.0 - 1.0)
/// 返回 None 表示 "none"（透明）
pub fn parse_color(color: &str) -> Option<(f32, f32, f32)> {
    let color = color.trim();

    // fill="none"
    if color == "none" {
        return None;
    }

    // #RGB 或 #RRGGBB
    if color.starts_with('#') {
        return parse_hex(color);
    }

    // rgba(r, g, b, a)
    if color.starts_with("rgba(") {
        return parse_rgba(color);
    }

    // rgb(r, g, b)
    if color.starts_with("rgb(") {
        return parse_rgb(color);
    }

    // 颜色名
    COLOR_NAMES.get(&color.to_lowercase()).copied()
}

fn parse_hex(color: &str) -> Option<(f32, f32, f32)> {
    let hex = &color[1..];
    let (r, g, b) = match hex.len() {
        3 => {
            let r = u8::from_str_radix(&hex[0..1].repeat(2), 16).ok()?;
            let g = u8::from_str_radix(&hex[1..2].repeat(2), 16).ok()?;
            let b = u8::from_str_radix(&hex[2..3].repeat(2), 16).ok()?;
            (r, g, b)
        }
        6 => {
            let r = u8::from_str_radix(&hex[0..2], 16).ok()?;
            let g = u8::from_str_radix(&hex[2..4], 16).ok()?;
            let b = u8::from_str_radix(&hex[4..6], 16).ok()?;
            (r, g, b)
        }
        _ => return None,
    };
    Some((r as f32 / 255.0, g as f32 / 255.0, b as f32 / 255.0))
}

fn parse_rgba(color: &str) -> Option<(f32, f32, f32)> {
    let inner = color.strip_prefix("rgba(")?.strip_suffix(")")?;
    let parts: Vec<&str> = inner.split(',').collect();
    if parts.len() != 4 { return None; }
    let r: f32 = parts[0].trim().parse().ok()?;
    let g: f32 = parts[1].trim().parse().ok()?;
    let b: f32 = parts[2].trim().parse().ok()?;
    // 忽略 alpha
    Some((r / 255.0, g / 255.0, b / 255.0))
}

fn parse_rgb(color: &str) -> Option<(f32, f32, f32)> {
    let inner = color.strip_prefix("rgb(")?.strip_suffix(")")?;
    let parts: Vec<&str> = inner.split(',').collect();
    if parts.len() != 3 { return None; }
    let r: f32 = parts[0].trim().parse().ok()?;
    let g: f32 = parts[1].trim().parse().ok()?;
    let b: f32 = parts[2].trim().parse().ok()?;
    Some((r / 255.0, g / 255.0, b / 255.0))
}

pub fn color_to_pdf_rgb(color: &str) -> Option<(f32, f32, f32)> {
    // Check cache first
    if let Ok(cache) = COLOR_CACHE.lock() {
        if let Some(cached) = cache.get(color) {
            return *cached;
        }
    }

    let result = parse_color(color);

    // Store in cache
    if let Ok(mut cache) = COLOR_CACHE.lock() {
        if cache.len() < 1000 {
            cache.insert(color.to_string(), result);
        }
    }

    result
}