use std::path::Path;
use windows::{
    core::{Interface, PCWSTR, HRESULT},
    Win32::{
        System::{
            Com::{
                CoCreateInstance, CoInitializeEx, CoUninitialize,
                IPersistFile, CLSCTX_INPROC_SERVER, COINIT_APARTMENTTHREADED
            },
        },
        UI::Shell::{IShellLinkW, ShellLink},
    },
};

#[tauri::command]
pub fn create_shortcut(
    install_path: String,
    shortcut_name: String,
    exe_name: String
) -> Result<String, String> {
    unsafe {
        // 初始化COM库
        let com_result = CoInitializeEx(None, COINIT_APARTMENTTHREADED);
        let needs_uninit = com_result.is_ok() || com_result == HRESULT(0x80010106u32 as i32); // S_FALSE or RPC_E_CHANGED_MODE

        let result = create_shortcut_internal(&install_path, &shortcut_name, &exe_name);

        if needs_uninit {
            CoUninitialize();
        }

        result
    }
}

unsafe fn create_shortcut_internal(
    install_path: &str,
    shortcut_name: &str,
    exe_name: &str
) -> Result<String, String> {
    // 获取当前用户桌面路径
    let desktop_path = get_desktop_path()?;
    let shortcut_file = format!("{}.lnk", shortcut_name);
    let shortcut_full_path = Path::new(&desktop_path).join(&shortcut_file);

    // 构建目标程序路径
    let target_path = Path::new(install_path).join(exe_name);
    if !target_path.exists() {
        return Err(format!("目标程序不存在: {}", target_path.display()));
    }

    // 创建IShellLink对象
    let shell_link: IShellLinkW = CoCreateInstance(
        &ShellLink,
        None,
        CLSCTX_INPROC_SERVER
    ).map_err(|e| format!("创建ShellLink失败: {:?}", e))?;

    // 设置快捷方式属性
    set_shell_link_properties(&shell_link, &target_path, install_path)?;

    // 保存快捷方式
    save_shortcut(&shell_link, &shortcut_full_path)?;

    Ok(format!("快捷方式创建成功: {}", shortcut_full_path.display()))
}

unsafe fn get_desktop_path() -> Result<String, String> {
    std::env::var("USERPROFILE")
        .map(|profile| format!("{}\\Desktop", profile))
        .or_else(|_| {
            std::env::var("USERNAME")
                .map(|username| format!("C:\\Users\\{}\\Desktop", username))
        })
        .map_err(|_| "无法获取用户桌面路径".to_string())
}

unsafe fn set_shell_link_properties(
    shell_link: &IShellLinkW,
    target_path: &Path,
    working_dir: &str
) -> Result<(), String> {
    // 设置目标路径
    let target_path_str = target_path.to_string_lossy();
    let wide_target: Vec<u16> = to_wide_string(&target_path_str);

    // 用 map_err + ? 处理错误并转换为 String
    shell_link
        .SetPath(PCWSTR(wide_target.as_ptr()))
        .map_err(|e| format!("设置目标路径失败: {:?}", e))?;

    // 设置工作目录
    let wide_working_dir: Vec<u16> = to_wide_string(working_dir);
    shell_link
        .SetWorkingDirectory(PCWSTR(wide_working_dir.as_ptr()))
        .map_err(|e| format!("设置工作目录失败: {:?}", e))?;

    // 设置描述
    let description = "NoPJ创建的快捷方式 - nopj.cn";
    let wide_desc: Vec<u16> = to_wide_string(description);
    shell_link
        .SetDescription(PCWSTR(wide_desc.as_ptr()))
        .map_err(|e| format!("设置描述失败: {:?}", e))?;

    Ok(())
}


unsafe fn save_shortcut(
    shell_link: &IShellLinkW,
    shortcut_path: &Path
) -> Result<(), String> {
    // 转换为 IPersistFile 接口
    let persist_file: IPersistFile = shell_link
        .cast()
        .map_err(|e| format!("接口转换失败: {:?}", e))?;

    // 保存文件
    let path_str = shortcut_path.to_string_lossy();
    let wide_path: Vec<u16> = to_wide_string(&path_str);

    // Save 可能返回 windows::core::Result<()>，同样用 map_err ? 处理
    persist_file
        .Save(PCWSTR(wide_path.as_ptr()), true)
        .map_err(|e| format!("保存快捷方式失败: {:?}", e))?;

    Ok(())
}

fn to_wide_string(s: &str) -> Vec<u16> {
    s.encode_utf16().chain(std::iter::once(0)).collect()
}
