use crossterm::event::KeyCode;
use rdev::EventType;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// 每日统计数据结构，用于序列化保存到本地 JSON。
#[derive(Serialize, Deserialize, Default, Clone)]
pub struct Record {
    pub total_keys: u64,
    pub total_mouse: u64,
    pub peak_kps: f64,
    pub peak_cps: f64,
    pub key_counts: HashMap<String, u64>,
    pub mouse_counts: HashMap<String, u64>,
    pub backspace_count: u64,
    pub delete_count: u64,
}

/// 单个小时统计。
#[derive(Serialize, Deserialize, Default, Clone)]
pub struct HourlyRecord {
    pub total_keys: u64,
    pub total_mouse: u64,
}

/// 一天 24 小时的统计。
#[derive(Serialize, Deserialize, Default, Clone)]
pub struct DailyHourly {
    pub date: String,
    pub hours: Vec<HourlyRecord>,
}

impl DailyHourly {
    pub fn new(date: String) -> Self {
        Self {
            date,
            hours: vec![HourlyRecord::default(); 24],
        }
    }
}

/// 单窗口趋势缓存。
#[derive(Serialize, Deserialize, Default, Clone)]
pub struct TrendCache {
    pub updated_at: String,
    pub window_days: u32,
    pub days: Vec<(String, Record)>,
}

/// 多窗口趋势缓存集合。
#[derive(Serialize, Deserialize, Default)]
pub struct MultiTrendCache {
    pub caches: std::collections::HashMap<u32, TrendCache>,
}

impl MultiTrendCache {
    /// 获取指定窗口的缓存，不存在则返回 None。
    pub fn get(&self, window: u32) -> Option<&TrendCache> {
        self.caches.get(&window)
    }

    /// 确保指定窗口的缓存存在且为最新（按日期），否则通过 store 重建。
    pub fn ensure(&mut self, store: &crate::storage::Store, window: u32) {
        let today = chrono::Local::now().format("%Y-%m-%d").to_string();
        let needs_rebuild = match self.caches.get(&window) {
            Some(cache) => !cache.updated_at.starts_with(&today),
            None => true,
        };
        if needs_rebuild {
            self.caches
                .insert(window, store.rebuild_trend_cache(window));
        }
    }

    /// 清理不在指定集合中的窗口缓存。
    pub fn retain(&mut self, f: impl Fn(&u32) -> bool) {
        self.caches.retain(|k, _| f(k));
    }
}

/// 用户配置。首次启动时自动生成 `~/.tapstat/config.json`，
/// 所有字段均有 serde default，升级时缺失字段自动回退到默认值。
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Config {
    /// 覆盖默认数据目录（优先级低于环境变量 TAPSTAT_DATA_DIR）。
    #[serde(skip_serializing_if = "Option::is_none")]
    pub data_dir: Option<String>,

    /// 自动保存间隔（秒）。
    #[serde(default = "default_auto_save_interval")]
    pub auto_save_interval_secs: u64,

    /// 崩溃恢复快照间隔（秒）。
    #[serde(default = "default_quick_save_interval")]
    pub quick_save_interval_secs: u64,

    /// 小时级数据保留天数。
    #[serde(default = "default_hourly_keep_days")]
    pub hourly_keep_days: i64,

    /// 启动时默认显示的趋势窗口天数。
    #[serde(default = "default_trend_window")]
    pub default_trend_window: u32,

    /// 按 T 键循环切换的趋势窗口列表。
    #[serde(default = "default_trend_windows")]
    pub trend_windows: Vec<u32>,

    /// 无输入权限提示等待时间（秒）。
    #[serde(default = "default_permission_warning_delay")]
    pub permission_warning_delay_secs: u64,

    /// 底部提示消息持续时间（秒）。
    #[serde(default = "default_message_display_secs")]
    pub message_display_secs: u64,
}

fn default_auto_save_interval() -> u64 {
    300
}
fn default_quick_save_interval() -> u64 {
    30
}
fn default_hourly_keep_days() -> i64 {
    30
}
fn default_trend_window() -> u32 {
    7
}
fn default_trend_windows() -> Vec<u32> {
    vec![7]
}
fn default_permission_warning_delay() -> u64 {
    5
}
fn default_message_display_secs() -> u64 {
    3
}

impl Default for Config {
    fn default() -> Self {
        Self {
            data_dir: None,
            auto_save_interval_secs: default_auto_save_interval(),
            quick_save_interval_secs: default_quick_save_interval(),
            hourly_keep_days: default_hourly_keep_days(),
            default_trend_window: default_trend_window(),
            trend_windows: default_trend_windows(),
            permission_warning_delay_secs: default_permission_warning_delay(),
            message_display_secs: default_message_display_secs(),
        }
    }
}

/// 主视图模式。
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum ViewMode {
    Dashboard,
    Hourly,
    Trend,
    Calendar,
}

/// 应用内部事件类型。Tick 用于驱动 UI 刷新，Input 来自全局输入监听，Key 来自终端按键。
pub enum AppEvent {
    Tick,
    Input(EventType),
    Key(KeyCode),
}
