use crate::pin_mode;
use crate::runner::{self, Shortcut};
use crate::storage;
use tauri::{AppHandle, Manager, PhysicalSize};
use tauri_plugin_notification::NotificationExt;

/// 统一的命令返回错误类型（serde 友好）
#[derive(Debug, thiserror::Error)]
pub enum CmdError {
    #[error("{0}")]
    Anyhow(String),
}

impl From<anyhow::Error> for CmdError {
    fn from(e: anyhow::Error) -> Self {
        CmdError::Anyhow(format!("{e:#}"))
    }
}

impl serde::Serialize for CmdError {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        serializer.serialize_str(&self.to_string())
    }
}

type CmdResult<T> = Result<T, CmdError>;

/// 读取整份 JSON 数据返回给前端
#[tauri::command]
pub fn load_state(app: AppHandle) -> CmdResult<String> {
    Ok(storage::read_state(&app)?)
}

/// 前端整体保存 JSON
#[tauri::command]
pub fn save_state(app: AppHandle, json: String) -> CmdResult<()> {
    storage::write_state(&app, &json)?;
    Ok(())
}

/// 执行一个快捷方式（app/cmd/powershell；url 由前端 opener 处理）
#[tauri::command]
pub fn run_shortcut(shortcut: Shortcut) -> CmdResult<()> {
    runner::execute(&shortcut)?;
    Ok(())
}

/// 切换主窗口的"始终置顶"
#[tauri::command]
pub fn set_always_on_top(app: AppHandle, on: bool) -> CmdResult<()> {
    if let Some(win) = app.get_webview_window("main") {
        win.set_always_on_top(on)
            .map_err(|e| CmdError::Anyhow(e.to_string()))?;
    }
    Ok(())
}

/// 调整主窗口大小（折叠/展开抽屉时使用）
#[tauri::command]
pub fn set_window_size(app: AppHandle, width: u32, height: u32) -> CmdResult<()> {
    if let Some(win) = app.get_webview_window("main") {
        win.set_size(PhysicalSize::new(width, height))
            .map_err(|e| CmdError::Anyhow(e.to_string()))?;
    }
    Ok(())
}

/// 在文件资源管理器中打开数据目录
#[tauri::command]
pub fn open_data_dir(app: AppHandle) -> CmdResult<String> {
    let path = storage::data_path(&app)?;
    let dir = path
        .parent()
        .ok_or_else(|| CmdError::Anyhow("no parent dir".into()))?;
    // 用 Windows explorer 打开目录
    #[cfg(target_os = "windows")]
    {
        use std::process::Command;
        Command::new("explorer.exe")
            .arg(dir)
            .spawn()
            .map_err(|e| CmdError::Anyhow(e.to_string()))?;
    }
    Ok(dir.display().to_string())
}

/// 钉子模式：开启后窗口默认点击穿透，仅钉子按钮热区可点击
#[tauri::command]
pub fn set_pin_mode(app: AppHandle, on: bool) -> CmdResult<()> {
    pin_mode::set_pin_mode(&app, on).map_err(CmdError::Anyhow)?;
    Ok(())
}

/// 更新钉子按钮在窗口内的热区（供轮询判断何时恢复接收鼠标）
#[tauri::command]
pub fn update_pin_hotzone(x: f64, y: f64, width: f64, height: f64, active: bool) -> CmdResult<()> {
    pin_mode::set_hotzone(x, y, width, height, active);
    Ok(())
}

/// 发送系统通知（番茄钟阶段切换提示）
#[tauri::command]
pub fn notify_user(app: AppHandle, title: String, body: String) -> CmdResult<()> {
    app.notification()
        .builder()
        .title(&title)
        .body(&body)
        .show()
        .map_err(|e| CmdError::Anyhow(e.to_string()))?;
    Ok(())
}
