use std::collections::HashMap;
use std::fs;
use std::io;
use std::path::PathBuf;

use chrono::Local;

use crate::storage::{default_data_dir, desktop_dir};

/// 根据按键次数占总按键数的比例，返回 6 级热力颜色之一。
pub fn heat_color(count: u64, total: u64) -> &'static str {
    if total == 0 || count == 0 {
        return "#e3f2fd";
    }
    let ratio = count as f64 / total as f64;
    match ratio {
        r if r > 0.06 => "#d32f2f",  // 深红：占比 > 6%
        r if r > 0.03 => "#ff7043",  // 橙红：3% ~ 6%
        r if r > 0.015 => "#ffee58", // 黄色：1.5% ~ 3%
        r if r > 0.005 => "#66bb6a", // 绿色：0.5% ~ 1.5%
        r if r > 0.001 => "#90caf9", // 浅蓝：0.1% ~ 0.5%
        _ => "#e3f2fd",              // 冰蓝：< 0.1%
    }
}

// =============================================================================
// 键盘布局数据
// =============================================================================

/// 单个键帽定义（相对坐标，单位 px）。
/// label 为空串时，渲染时用 `os_label(name)` 按系统显示。
struct KeyDef {
    name: &'static str,
    label: &'static str,
    x: i32,
    y: i32,
    w: i32,
    h: i32,
}

impl KeyDef {
    const fn new(name: &'static str, label: &'static str, x: i32, y: i32, w: i32, h: i32) -> Self {
        Self {
            name,
            label,
            x,
            y,
            w,
            h,
        }
    }

    /// modifier 键：标签由运行时 `os_label()` 决定。
    const fn os(name: &'static str, x: i32, y: i32, w: i32, h: i32) -> Self {
        Self {
            name,
            label: "",
            x,
            y,
            w,
            h,
        }
    }
}

// ── F 功能区 ──
const F_KEYS: &[KeyDef] = &[
    KeyDef::new("Esc", "Esc", 0, -50, 40, 40),
    // Esc/F1 间距 32px，组内间距 4px，组间间距 32px
    KeyDef::new("F1", "F1", 72, -50, 40, 40),
    KeyDef::new("F2", "F2", 116, -50, 40, 40),
    KeyDef::new("F3", "F3", 160, -50, 40, 40),
    KeyDef::new("F4", "F4", 204, -50, 40, 40),
    KeyDef::new("F5", "F5", 276, -50, 40, 40),
    KeyDef::new("F6", "F6", 320, -50, 40, 40),
    KeyDef::new("F7", "F7", 364, -50, 40, 40),
    KeyDef::new("F8", "F8", 408, -50, 40, 40),
    KeyDef::new("F9", "F9", 484, -50, 40, 40),
    KeyDef::new("F10", "F10", 528, -50, 40, 40),
    KeyDef::new("F11", "F11", 572, -50, 40, 40),
    KeyDef::new("F12", "F12", 616, -50, 40, 40),
    // F12 右边缘 656，与主键区 Backspace 对齐
];

// ── 主键区 Row 0（无 F 区）──
const ROW0_NO_F: &[KeyDef] = &[
    KeyDef::new("Esc", "Esc", 0, 0, 40, 40),
    KeyDef::new("`", "`", 44, 0, 40, 40),
    KeyDef::new("1", "1", 88, 0, 40, 40),
    KeyDef::new("2", "2", 132, 0, 40, 40),
    KeyDef::new("3", "3", 176, 0, 40, 40),
    KeyDef::new("4", "4", 220, 0, 40, 40),
    KeyDef::new("5", "5", 264, 0, 40, 40),
    KeyDef::new("6", "6", 308, 0, 40, 40),
    KeyDef::new("7", "7", 352, 0, 40, 40),
    KeyDef::new("8", "8", 396, 0, 40, 40),
    KeyDef::new("9", "9", 440, 0, 40, 40),
    KeyDef::new("0", "0", 484, 0, 40, 40),
    KeyDef::new("-", "-", 528, 0, 40, 40),
    KeyDef::new("=", "=", 572, 0, 40, 40),
    KeyDef::new("Backspace", "⌫", 616, 0, 40, 40),
];

// ── 主键区 Row 0（有 F 区）──
const ROW0_HAS_F: &[KeyDef] = &[
    KeyDef::new("`", "`", 0, 0, 40, 40),
    KeyDef::new("1", "1", 44, 0, 40, 40),
    KeyDef::new("2", "2", 88, 0, 40, 40),
    KeyDef::new("3", "3", 132, 0, 40, 40),
    KeyDef::new("4", "4", 176, 0, 40, 40),
    KeyDef::new("5", "5", 220, 0, 40, 40),
    KeyDef::new("6", "6", 264, 0, 40, 40),
    KeyDef::new("7", "7", 308, 0, 40, 40),
    KeyDef::new("8", "8", 352, 0, 40, 40),
    KeyDef::new("9", "9", 396, 0, 40, 40),
    KeyDef::new("0", "0", 440, 0, 40, 40),
    KeyDef::new("-", "-", 484, 0, 40, 40),
    KeyDef::new("=", "=", 528, 0, 40, 40),
    KeyDef::new("Backspace", "⌫", 572, 0, 84, 40),
];

// ── 主键区 Row 1 ──
const ROW1: &[KeyDef] = &[
    KeyDef::new("Tab", "Tab", 0, 44, 62, 40),
    KeyDef::new("Q", "Q", 66, 44, 40, 40),
    KeyDef::new("W", "W", 110, 44, 40, 40),
    KeyDef::new("E", "E", 154, 44, 40, 40),
    KeyDef::new("R", "R", 198, 44, 40, 40),
    KeyDef::new("T", "T", 242, 44, 40, 40),
    KeyDef::new("Y", "Y", 286, 44, 40, 40),
    KeyDef::new("U", "U", 330, 44, 40, 40),
    KeyDef::new("I", "I", 374, 44, 40, 40),
    KeyDef::new("O", "O", 418, 44, 40, 40),
    KeyDef::new("P", "P", 462, 44, 40, 40),
    KeyDef::new("[", "[", 506, 44, 40, 40),
    KeyDef::new("]", "]", 550, 44, 40, 40),
    KeyDef::new("\\", "\\", 594, 44, 62, 40),
];

// ── 主键区 Row 2 ──
const ROW2: &[KeyDef] = &[
    KeyDef::new("CapsLock", "Caps", 0, 88, 73, 40),
    KeyDef::new("A", "A", 77, 88, 40, 40),
    KeyDef::new("S", "S", 121, 88, 40, 40),
    KeyDef::new("D", "D", 165, 88, 40, 40),
    KeyDef::new("F", "F", 209, 88, 40, 40),
    KeyDef::new("G", "G", 253, 88, 40, 40),
    KeyDef::new("H", "H", 297, 88, 40, 40),
    KeyDef::new("J", "J", 341, 88, 40, 40),
    KeyDef::new("K", "K", 385, 88, 40, 40),
    KeyDef::new("L", "L", 429, 88, 40, 40),
    KeyDef::new(";", ";", 473, 88, 40, 40),
    KeyDef::new("'", "'", 517, 88, 40, 40),
    KeyDef::new("Enter", "↵", 561, 88, 95, 40),
];

// ── 主键区 Row 3 ──
const ROW3: &[KeyDef] = &[
    KeyDef::os("ShiftLeft", 0, 132, 95, 40),
    KeyDef::new("Z", "Z", 99, 132, 40, 40),
    KeyDef::new("X", "X", 143, 132, 40, 40),
    KeyDef::new("C", "C", 187, 132, 40, 40),
    KeyDef::new("V", "V", 231, 132, 40, 40),
    KeyDef::new("B", "B", 275, 132, 40, 40),
    KeyDef::new("N", "N", 319, 132, 40, 40),
    KeyDef::new("M", "M", 363, 132, 40, 40),
    KeyDef::new(",", ",", 407, 132, 40, 40),
    KeyDef::new(".", ".", 451, 132, 40, 40),
    KeyDef::new("/", "/", 495, 132, 40, 40),
    KeyDef::os("ShiftRight", 539, 132, 117, 40),
];

// ── 主键区 Row 4（macOS: Ctrl-Option-Command-Space-Command-Option-Ctrl）──
const ROW4_MACOS: &[KeyDef] = &[
    KeyDef::os("CtrlLeft", 0, 176, 52, 40),
    KeyDef::os("AltLeft", 56, 176, 52, 40),
    KeyDef::os("CmdLeft", 112, 176, 52, 40),
    KeyDef::new("Space", "Space", 168, 176, 271, 40),
    KeyDef::os("CmdRight", 443, 176, 52, 40),
    KeyDef::os("AltRight", 499, 176, 52, 40),
    KeyDef::os("CtrlRight", 555, 176, 52, 40),
    KeyDef::new("Fn", "Fn", 611, 176, 45, 40),
];

// ── 主键区 Row 4（Windows/Linux: Ctrl-Win-Alt-Space-Alt-Win-Ctrl）──
const ROW4_WIN_LINUX: &[KeyDef] = &[
    KeyDef::os("CtrlLeft", 0, 176, 52, 40),
    KeyDef::os("CmdLeft", 56, 176, 52, 40),
    KeyDef::os("AltLeft", 112, 176, 52, 40),
    KeyDef::new("Space", "Space", 168, 176, 271, 40),
    KeyDef::os("AltRight", 443, 176, 52, 40),
    KeyDef::os("CmdRight", 499, 176, 52, 40),
    KeyDef::os("CtrlRight", 555, 176, 52, 40),
    KeyDef::new("Fn", "Fn", 611, 176, 45, 40),
];

// ── 编辑键区（有 F 区）──
const EDIT_HAS_F: &[KeyDef] = &[
    KeyDef::new("PrtSc", "PrtSc", 680, -50, 40, 40),
    KeyDef::new("ScrLk", "ScrLk", 724, -50, 40, 40),
    KeyDef::new("Pause", "Pause", 768, -50, 40, 40),
    KeyDef::new("Insert", "Ins", 680, 0, 40, 40),
    KeyDef::new("Home", "Home", 724, 0, 40, 40),
    KeyDef::new("PageUp", "PgUp", 768, 0, 40, 40),
    KeyDef::new("Delete", "Del", 680, 44, 40, 40),
    KeyDef::new("End", "End", 724, 44, 40, 40),
    KeyDef::new("PageDown", "PgDn", 768, 44, 40, 40),
];

// ── 编辑键区（无 F 区）──
const EDIT_NO_F: &[KeyDef] = &[
    KeyDef::new("PrtSc", "PrtSc", 680, 0, 40, 40),
    KeyDef::new("ScrLk", "ScrLk", 724, 0, 40, 40),
    KeyDef::new("Pause", "Pause", 768, 0, 40, 40),
    KeyDef::new("Insert", "Ins", 680, 44, 40, 40),
    KeyDef::new("Home", "Home", 724, 44, 40, 40),
    KeyDef::new("PageUp", "PgUp", 768, 44, 40, 40),
    KeyDef::new("Delete", "Del", 680, 88, 40, 40),
    KeyDef::new("End", "End", 724, 88, 40, 40),
    KeyDef::new("PageDown", "PgDn", 768, 88, 40, 40),
];

// ── 方向键簇 ──
const ARROWS: &[KeyDef] = &[
    KeyDef::new("↑", "↑", 724, 132, 40, 40),
    KeyDef::new("←", "←", 680, 176, 40, 40),
    KeyDef::new("↓", "↓", 724, 176, 40, 40),
    KeyDef::new("→", "→", 768, 176, 40, 40),
];

// ── 数字小键盘 ──
const NUMPAD: &[KeyDef] = &[
    KeyDef::new("NumLock", "NumLk", 880, 0, 40, 40),
    KeyDef::new("Kp/", "/", 924, 0, 40, 40),
    KeyDef::new("Kp*", "*", 968, 0, 40, 40),
    KeyDef::new("Kp-", "-", 1012, 0, 40, 40),
    KeyDef::new("Kp7", "7", 880, 44, 40, 40),
    KeyDef::new("Kp8", "8", 924, 44, 40, 40),
    KeyDef::new("Kp9", "9", 968, 44, 40, 40),
    KeyDef::new("Kp+", "+", 1012, 44, 40, 84),
    KeyDef::new("Kp4", "4", 880, 88, 40, 40),
    KeyDef::new("Kp5", "5", 924, 88, 40, 40),
    KeyDef::new("Kp6", "6", 968, 88, 40, 40),
    KeyDef::new("Kp1", "1", 880, 132, 40, 40),
    KeyDef::new("Kp2", "2", 924, 132, 40, 40),
    KeyDef::new("Kp3", "3", 968, 132, 40, 40),
    KeyDef::new("KpEnter", "↵", 1012, 132, 40, 84),
    KeyDef::new("Kp0", "0", 880, 176, 84, 40),
    KeyDef::new("KpDel", ".", 968, 176, 40, 40),
];

// =============================================================================
// 主函数
// =============================================================================

/// 根据操作系统返回 modifier 键的显示标签。
fn os_label(name: &'static str) -> &'static str {
    match std::env::consts::OS {
        "macos" => match name {
            "CmdLeft" | "CmdRight" => "⌘",
            "AltLeft" | "AltRight" => "⌥",
            "CtrlLeft" | "CtrlRight" => "⌃",
            "ShiftLeft" | "ShiftRight" => "⇧",
            _ => name,
        },
        "windows" => match name {
            "CmdLeft" | "CmdRight" => "Win",
            _ => name,
        },
        _ => match name {
            "CmdLeft" | "CmdRight" => "Super",
            _ => name,
        },
    }
}

/// 根据 key_counts 生成 HTML 和 SVG 键盘热图，保存到桌面。
/// `date_label` 为 Some 时，文件名和标题会带上日期后缀。
/// 返回生成的 HTML 文件路径。
pub fn export_heatmap(
    counts: &HashMap<String, u64>,
    total_keys: u64,
    date_label: Option<&str>,
) -> io::Result<PathBuf> {
    let mut counts = counts.clone();
    crate::storage::split_modifier_counts(&mut counts);

    let total = total_keys;
    let mut dir = desktop_dir();
    if !dir.exists() {
        dir = default_data_dir();
    }
    if !dir.exists() {
        fs::create_dir_all(&dir)?;
    }
    let (html_name, svg_name, title_suffix) = match date_label {
        Some(d) => (
            format!("tapstat-heatmap-{}.html", d),
            format!("tapstat-heatmap-{}.svg", d),
            format!(" · {}", d),
        ),
        None => (
            "tapstat-heatmap.html".to_string(),
            "tapstat-heatmap.svg".to_string(),
            String::new(),
        ),
    };
    let html_path = dir.join(&html_name);
    let svg_path = dir.join(&svg_name);

    let mut keys_svg_parts: Vec<String> = Vec::new();

    // 自适应布局检测：根据用户实际按过的键决定画布大小
    let has_f = counts
        .keys()
        .any(|k| k == "Esc" || (k.starts_with("F") && k.len() <= 3 && k != "Fn"));
    let has_numpad = counts.keys().any(|k| k.starts_with("Kp") || k == "NumLock");
    let has_edit = counts.keys().any(|k| {
        matches!(
            k.as_str(),
            "Insert"
                | "Home"
                | "PageUp"
                | "Delete"
                | "End"
                | "PageDown"
                | "PrtSc"
                | "ScrLk"
                | "Pause"
        )
    });

    let svg_width = if has_numpad { 1100 } else { 850 };
    let svg_height = if has_f { 300 } else { 250 };
    let base_x = 20;
    let base_y = if has_f { 55 } else { 10 };

    // 辅助闭包：向 SVG 中添加一个键帽矩形和文本
    let mut add_key = |name: &str, label: &str, x: i32, y: i32, w: i32, h: i32| {
        let count = counts.get(name).copied().unwrap_or(0);
        let color = heat_color(count, total);
        let tooltip = if total > 0 {
            format!(
                "{}: {} 次 ({:.2}%)",
                name,
                count,
                (count as f64 / total as f64 * 100.0).min(100.0)
            )
        } else {
            format!("{}: 0 次", name)
        };
        keys_svg_parts.push(format!(
            r##"<g class="key" data-tooltip="{}" transform="translate({}, {})">
                <title>{}</title>
                <rect x="0" y="0" width="{}" height="{}" rx="4" fill="{}" stroke="#444" stroke-width="1"/>
                <text x="{}" y="{}" text-anchor="middle" font-size="10" fill="#222" font-family="system-ui, sans-serif">{}</text>
            </g>"##,
            tooltip,
            base_x + x,
            base_y + y,
            tooltip,
            w,
            h,
            color,
            w / 2,
            h / 2 + 4,
            label
        ));
    };

    // 批量渲染一组键
    let mut render = |keys: &[KeyDef]| {
        for k in keys {
            let label = if k.label.is_empty() {
                os_label(k.name)
            } else {
                k.label
            };
            add_key(k.name, label, k.x, k.y, k.w, k.h);
        }
    };

    // ── F 功能区（条件渲染）──
    if has_f {
        render(F_KEYS);
    }

    // ── 主键区 5 行 ──
    if !has_f {
        render(ROW0_NO_F);
    } else {
        render(ROW0_HAS_F);
    }
    render(ROW1);
    render(ROW2);
    render(ROW3);
    render(if std::env::consts::OS == "macos" {
        ROW4_MACOS
    } else {
        ROW4_WIN_LINUX
    });

    // ── 编辑键区（条件渲染）──
    if has_edit {
        render(if has_f { EDIT_HAS_F } else { EDIT_NO_F });
    }

    // ── 方向键簇（总是渲染）──
    render(ARROWS);

    // ── 数字小键盘（条件渲染）──
    if has_numpad {
        render(NUMPAD);
    }

    let now = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();

    // 生成独立 SVG（用 <title> 实现原生 tooltip）
    let svg_only = format!(
        r##"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="{svg_width}" height="{svg_height}" viewBox="0 0 {svg_width} {svg_height}">
  <rect width="{svg_width}" height="{svg_height}" fill="#2a2a2a" rx="12"/>
  <text x="{title_x}" y="30" text-anchor="middle" font-size="18" fill="#4fc3f7" font-family="system-ui, sans-serif">TapStat 键盘热图{title_suffix}</text>
  <text x="{title_x}" y="52" text-anchor="middle" font-size="12" fill="#aaa" font-family="system-ui, sans-serif">总按键数: {total} · 生成时间: {now}</text>
  <g transform="translate(20, 70)">
    {keys_svg}
  </g>
</svg>"##,
        svg_width = svg_width,
        svg_height = svg_height,
        title_x = svg_width / 2,
        total = total,
        now = now,
        title_suffix = title_suffix,
        keys_svg = keys_svg_parts.join("")
    );

    // 生成带交互的 HTML 版本
    let html = format!(
        r#"<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>TapStat 键盘热图</title>
    <style>
        body {{
            margin: 0;
            padding: 40px;
            background: #1e1e1e;
            color: #eee;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            display: flex;
            flex-direction: column;
            align-items: center;
        }}
        h1 {{ margin: 0 0 10px; font-size: 24px; color: #4fc3f7; }}
        .meta {{ color: #aaa; font-size: 14px; margin-bottom: 30px; }}
        .keyboard {{
            background: #2a2a2a;
            padding: 20px;
            border-radius: 12px;
            box-shadow: 0 8px 32px rgba(0,0,0,0.4);
            position: relative;
        }}
        .key {{
            cursor: pointer;
            transition: opacity 0.15s;
        }}
        .key:hover {{
            opacity: 0.85;
        }}
        .key text {{
            pointer-events: none;
            font-weight: 500;
        }}
        #tooltip {{
            position: absolute;
            background: rgba(0,0,0,0.9);
            color: #fff;
            padding: 8px 12px;
            border-radius: 6px;
            font-size: 13px;
            pointer-events: none;
            white-space: nowrap;
            opacity: 0;
            transition: opacity 0.15s;
            border: 1px solid #555;
            z-index: 100;
        }}
        .legend {{
            margin-top: 24px;
            display: flex;
            align-items: center;
            gap: 8px;
            font-size: 13px;
            color: #bbb;
        }}
        .legend-box {{
            width: 20px;
            height: 20px;
            border-radius: 4px;
            border: 1px solid #444;
        }}
    </style>
</head>
<body>
    <h1>TapStat 键盘热图{title_suffix}</h1>
    <div class="meta">总按键数: {total} · 生成时间: {now}</div>
    <div class="keyboard">
        <svg width="{svg_width}" height="{svg_height}" viewBox="0 0 {svg_width} {svg_height}">
            {keys_svg}
        </svg>
        <div id="tooltip"></div>
    </div>
    <div class="legend">
        <span>低</span>
        <div class="legend-box" style="background:#e3f2fd"></div>
        <div class="legend-box" style="background:#90caf9"></div>
        <div class="legend-box" style="background:#66bb6a"></div>
        <div class="legend-box" style="background:#ffee58"></div>
        <div class="legend-box" style="background:#ff7043"></div>
        <div class="legend-box" style="background:#d32f2f"></div>
        <span>高</span>
    </div>
    <script>
        const tooltip = document.getElementById('tooltip');
        document.querySelectorAll('.key').forEach(key => {{
            key.addEventListener('mouseenter', () => {{
                tooltip.textContent = key.dataset.tooltip;
                tooltip.style.opacity = '1';
            }});
            key.addEventListener('mousemove', e => {{
                const rect = key.closest('.keyboard').getBoundingClientRect();
                tooltip.style.left = (e.clientX - rect.left + 12) + 'px';
                tooltip.style.top = (e.clientY - rect.top - 36) + 'px';
            }});
            key.addEventListener('mouseleave', () => {{
                tooltip.style.opacity = '0';
            }});
        }});
    </script>
</body>
</html>"#,
        svg_width = svg_width,
        svg_height = svg_height,
        total = total,
        now = now,
        title_suffix = title_suffix,
        keys_svg = keys_svg_parts.join("")
    );

    fs::write(&html_path, html)?;
    fs::write(&svg_path, svg_only)?;
    Ok(html_path)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_heat_color_zero() {
        assert_eq!(heat_color(0, 100), "#e3f2fd");
        assert_eq!(heat_color(5, 0), "#e3f2fd");
    }

    #[test]
    fn test_heat_color_tiers() {
        let total = 10_000;
        assert_eq!(heat_color(10, total), "#e3f2fd"); // 0.1% 以下
        assert_eq!(heat_color(20, total), "#90caf9"); // 0.1% ~ 0.5%
        assert_eq!(heat_color(80, total), "#66bb6a"); // 0.5% ~ 1.5%
        assert_eq!(heat_color(200, total), "#ffee58"); // 1.5% ~ 3%
        assert_eq!(heat_color(400, total), "#ff7043"); // 3% ~ 6%
        assert_eq!(heat_color(700, total), "#d32f2f"); // > 6%
    }
}
