//! dudu 桌面端（Tauri 2）。模块划分见 doc/frontend-design.html 4.1。

pub mod api;
pub mod audio;
pub mod dictation;
pub mod inject;
pub mod metrics;
pub mod settings;
pub mod ws;

use tauri::tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent};
use tauri::Manager;
use tauri_plugin_global_shortcut::{Shortcut, ShortcutState};

/// 托盘图标 rect → 菜单窗口左上角物理坐标。
/// macOS 系统菜单习惯：左缘对齐图标左缘、紧贴菜单栏下方；
/// 菜单超出屏幕右缘时整体左收（12A 实测反馈：居中定位偏左、间隙偏大）。
fn tray_menu_position(
    rect: &tauri::Rect,
    scale: f64,
    win_width: f64,
    screen_right: Option<f64>,
) -> (f64, f64) {
    let (x, y) = match rect.position {
        tauri::Position::Physical(p) => (p.x as f64, p.y as f64),
        tauri::Position::Logical(p) => (p.x * scale, p.y * scale),
    };
    let (_w, h) = match rect.size {
        tauri::Size::Physical(s) => (s.width as f64, s.height as f64),
        tauri::Size::Logical(s) => (s.width * scale, s.height * scale),
    };
    let mut mx = x;
    if let Some(right) = screen_right {
        if mx + win_width > right {
            mx = right - win_width - 8.0 * scale;
        }
    }
    (mx, y + h)
}

/// 左键点击托盘图标 → 在图标位置弹出 / 收起自绘菜单窗（11B）。
fn toggle_tray_menu(app: &tauri::AppHandle, rect: &tauri::Rect) {
    let Some(w) = app.get_webview_window("tray") else {
        return;
    };
    if w.is_visible().unwrap_or(false) {
        let _ = w.hide();
        return;
    }
    let scale = w.scale_factor().unwrap_or(1.0);
    let win_width = w
        .outer_size()
        .map(|s| s.width as f64)
        .unwrap_or(248.0 * scale);
    let screen_right = w.current_monitor().ok().flatten().map(|m| {
        m.position().x as f64 + m.size().width as f64
    });
    let (x, y) = tray_menu_position(rect, scale, win_width, screen_right);
    let _ = w.set_position(tauri::PhysicalPosition::new(x, y));
    let _ = w.show();
    let _ = w.set_focus(); // 获焦后才能在失焦时自动收起
}

pub fn run() {
    env_logger::init();
    tauri::Builder::default()
        .plugin(
            tauri_plugin_global_shortcut::Builder::new()
                .with_handler(|app, _shortcut: &Shortcut, event| {
                    match event.state() {
                        ShortcutState::Pressed => dictation::start(app),
                        ShortcutState::Released => dictation::stop(app, false),
                    }
                })
                .build(),
        )
        .on_window_event(|window, event| match event {
            // 托盘菜单窗失焦自动收起
            tauri::WindowEvent::Focused(false) if window.label() == "tray" => {
                let _ = window.hide();
            }
            // 常驻托盘：功能窗口"关闭"仅隐藏，应用不退出
            tauri::WindowEvent::CloseRequested { api, .. } => {
                match window.label() {
                    "settings" | "login" | "feedback" => {
                        api.prevent_close();
                        let _ = window.hide();
                    }
                    "onboarding" => {
                        // 关闭引导窗 = 完成引导（11F）
                        api.prevent_close();
                        api::finish_onboarding(window.app_handle().clone());
                    }
                    _ => {}
                }
            }
            _ => {}
        })
        .setup(|app| {
            let handle = app.handle().clone();
            // dudu 是托盘应用（无主窗口）：设为 Accessory 激活策略——菜单栏辅助 App，
            // 不占 Dock。这也是识别浮层能浮在其他 App 全屏之上的前提：标准 NSWindow
            // 靠 collectionBehavior 无法叠加到别的 App 全屏 Space（macOS 设计限制，
            // 见 Apple 论坛 26677 / tauri#11488），Accessory 策略 + CanJoinAllSpaces 才生效。
            #[cfg(target_os = "macos")]
            let _ = app.set_activation_policy(tauri::ActivationPolicy::Accessory);
            // 设置 → 管理状态
            app.manage(settings::SettingsStore::load(&handle));
            app.manage(dictation::DictationState::default());
            app.manage(dictation::CommitBuffer::default());
            app.manage(api::Paused::default());
            // WS 预连接 + 打点队列
            app.manage(ws::spawn(handle.clone()));
            app.manage(metrics::spawn(handle.clone()));
            // 系统托盘（11B）：左键弹出自绘菜单窗，tooltip 随录音状态切换
            let icon = app
                .default_window_icon()
                .cloned()
                .expect("missing app icon");
            TrayIconBuilder::with_id("main")
                .icon(icon)
                .tooltip("dudu — 就绪")
                .on_tray_icon_event(|tray, event| {
                    if let TrayIconEvent::Click {
                        button: MouseButton::Left,
                        button_state: MouseButtonState::Up,
                        rect,
                        ..
                    } = event
                    {
                        toggle_tray_menu(tray.app_handle(), &rect);
                    }
                })
                .build(app)?;
            // 注册 push-to-talk 快捷键
            let s = app.state::<settings::SettingsStore>().get();
            use tauri_plugin_global_shortcut::GlobalShortcutExt;
            if let Err(e) = app.global_shortcut().register(s.hotkey.as_str()) {
                log::error!("register hotkey failed: {e}");
            }
            // 识别浮层可浮在全屏 App 之上（终端/浏览器全屏时也能看到浮层）
            dictation::configure_overlay_spaces(&handle);
            // 首次启动 → 引导窗（11F）；之后均静默启动（仅托盘常驻）
            if !s.onboarding_done {
                if let Some(w) = app.get_webview_window("onboarding") {
                    let _ = w.show();
                    let _ = w.set_focus();
                }
            }
            Ok(())
        })
        .invoke_handler(tauri::generate_handler![
            settings::get_settings,
            settings::set_settings,
            settings::list_mic_devices,
            audio::request_microphone,
            inject::check_accessibility,
            inject::open_accessibility_settings,
            api::fetch_me,
            api::fetch_packs,
            api::login_qr_create,
            api::login_qr_poll,
            api::login_email_code,
            api::login_email,
            api::create_order,
            api::order_status,
            api::submit_feedback,
            api::is_paused,
            api::toggle_pause,
            api::open_settings,
            api::open_login,
            api::close_login,
            api::open_feedback,
            api::close_feedback,
            api::finish_onboarding,
            api::check_update,
            api::quit_app,
        ])
        .run(tauri::generate_context!())
        .expect("error while running dudu");
}
