use std::sync::Arc;

use crate::{
    constants::{common::*, window::*},
    storage::SessionStorage,
    window::{
        WindowLabel,
        derive::FloatListInfo,
        util::{get_monitor_for_window, show_windows_by_label},
    },
};
use tauri::{AppHandle, LogicalPosition, LogicalSize, Manager, Runtime, WebviewUrl, WebviewWindowBuilder, utils::config::BackgroundThrottlingPolicy};

/// 创建悬浮列表窗口（内部实现）
pub async fn create_float_list_window_impl<R: Runtime>(app: Arc<AppHandle<R>>, page_type: &str) -> Result<(), String> {
    let app_handle = Arc::clone(&app);
    let page_type_owned = page_type.to_string();
    if show_windows_by_label(app.as_ref(), WindowLabel::FLOAT_LIST) {
        return Ok(());
    }
    // 悬浮列表尺寸
    let float_info = calculate_float_info_sync(app.as_ref(), page_type);
    // 获取屏幕尺寸，优先为main窗口所在屏幕，主窗口没有打开时，才找主屏幕
    let monitor = get_monitor_for_window(app.as_ref())?;
    // 获取屏幕缩放因子
    let scale_factor = monitor.scale_factor();
    let page_size: LogicalSize<f64> = monitor.work_area().size.to_logical(scale_factor);
    let screen_width = page_size.width;
    let screen_height = page_size.height;
    let url = format!(
        "floating-list-window.html?isShowInteraction={}&isShowTutorship={}",
        float_info.is_show_interaction, float_info.is_show_tutorship
    );

    let label = WindowLabel::FLOAT_LIST.as_ref();
    // 创建悬浮球窗口，直接在初始化时设置好位置和尺寸
    let window = WebviewWindowBuilder::new(app.as_ref(), label, WebviewUrl::App(url.into()))
        .title("悬浮列表")
        .inner_size(float_info.width as f64, float_info.height as f64)
        .max_inner_size(float_info.width as f64, float_info.height as f64)
        .min_inner_size(float_info.width as f64, float_info.height as f64)
        .position(screen_width - float_info.width as f64, 0.0)
        .transparent(true)
        .visible_on_all_workspaces(true)
        .background_throttling(BackgroundThrottlingPolicy::Disabled)
        .decorations(false)
        .shadow(false)
        .focusable(true)
        .focused(false)
        .accept_first_mouse(true)
        .skip_taskbar(true)
        .always_on_top(true)
        .devtools(true)
        .build();

    let window = match window {
        Ok(w) => w,
        Err(e) => {
            log::error!("{} {}", MSG_FAILED_CREATE_FLOATING_LIST, e);
            return Err(format!("{} {}", MSG_FAILED_CREATE_FLOATING_LIST, e));
        }
    };

    #[cfg(not(target_os = "linux"))]
    {
        let _ = window.set_resizable(false);
    }
    #[cfg(target_os = "windows")]
    {
        let _ = window.set_size(LogicalSize::new(float_info.width as f64, float_info.height as f64));
    }

    // 窗口显示后等待200毫秒再执行动画
    tokio::spawn(async move {
        tokio::time::sleep(tokio::time::Duration::from_millis(200)).await;
        let _ = animate_to_bottom_right(&app_handle, window, screen_width as i32, screen_height as i32, &page_type_owned).await;
    });
    Ok(())
}

/// 根据用户登录状态和课程选择情况动态计算弹出窗口高度
pub fn calculate_float_info_sync<R: Runtime>(app: &AppHandle<R>, page_type: &str) -> FloatListInfo {
    // 默认基础项目数
    let mut item_num = 4;
    let mut is_show_interaction = false;
    let mut is_show_tutorship = false;

    // 获取会话存储实例
    let storage = match app.try_state::<SessionStorage>() {
        Some(s) => s,
        None => {
            log::error!("获取会话存储实例失败，使用默认值");
            let item_height = 64;
            let popup_height = item_height * item_num + 40;
            let popup_width = 60;
            return FloatListInfo {
                width: popup_width as u32,
                height: popup_height as u32,
                is_show_interaction,
                is_show_tutorship,
            };
        }
    };

    // 从会话存储中获取用户信息和课程信息来判断是否增加项目数
    let user_info_exists = match storage.get::<serde_json::Value>(STORAGE_KEY_USER_INFO) {
        Some(Ok(value)) => {
            // 检查必要的字段是否存在
            value.get("id").is_some()
        }
        _ => false,
    };
    let tutorship_info_exists = match storage.get::<serde_json::Value>(STORAGE_KEY_TUTORSHIP) {
        Some(Ok(value)) => {
            // 检查必要的字段是否存在
            value.get("id").is_some()
        }
        _ => false,
    };

    let course_info_exists = match storage.get::<serde_json::Value>(STORAGE_KEY_COURSE) {
        Some(Ok(value)) => {
            // 检查必要的字段是否存在
            value.get("id").is_some()
        }
        _ => false,
    };

    if user_info_exists {
        if page_type == "interaction" {
            is_show_interaction = true;
            // 如果能获取到用户信息和课程信息，则增加项目数
            if course_info_exists {
                item_num += 5;
            }
        } else if page_type == "tutorship" {
            // 如果能获取到用户信息和课程信息，则增加项目数
            if course_info_exists {
                is_show_interaction = true;
                item_num += 5;
            }
            if tutorship_info_exists {
                is_show_tutorship = true;
                item_num += 3;
            }
        }
    }
    // 每个item高度
    let item_height = 64;
    // 总高度 =  item高度 * 项目数 + 额外用于移动按钮和时间部分的高度
    let popup_height = item_height * item_num + 60;
    let popup_width = 60;

    // 返回计算得到的弹出窗口尺寸
    FloatListInfo {
        width: popup_width as u32,
        height: popup_height as u32,
        is_show_tutorship,
        is_show_interaction,
    }
}

/// 使用抛物线动画将窗口移动到右下角
pub async fn animate_to_bottom_right<R: Runtime>(
    app: &AppHandle<R>,
    window: tauri::WebviewWindow<R>,
    screen_width: i32,
    screen_height: i32,
    page_type: &str,
) -> Result<(), String> {
    // 获取当前窗口位置和大小
    let current_position_physical = window.outer_position().map_err(|e| format!("获取窗口位置失败: {}", e))?;
    let current_size_physical = window.outer_size().map_err(|e| format!("获取窗口大小失败: {}", e))?;
    let scale_factor = window.scale_factor().map_err(|e| format!("获取缩放因子失败: {}", e))?;

    // 转换为逻辑位置和大小
    let current_position = current_position_physical.to_logical::<i32>(scale_factor);
    let current_size = current_size_physical.to_logical::<i32>(scale_factor);

    let start_x = current_position.x;
    let start_y = current_position.y;

    // 计算目标位置（右下角）
    // 注意：screen_width 和 screen_height 已经在调用方考虑了缩放因子
    let end_x = screen_width - current_size.width;
    let end_y = screen_height - current_size.height - 120;

    // 计算移动距离
    let distance_x = (end_x - start_x) as f64;
    let distance_y = (end_y - start_y) as f64;

    // 动画参数
    let duration = 800; // 总动画时间（毫秒）
    let start_time = std::time::Instant::now();

    // 抛物线控制参数
    // 抛物线顶点高度偏移量（负值表示向下偏移，形成开口向上的抛物线）
    let apex_offset = -(distance_y.abs() * 0.3).min(200.0);

    // 执行动画
    loop {
        let elapsed = start_time.elapsed().as_millis() as u64;
        if elapsed >= duration {
            break;
        }

        let progress = (elapsed as f64) / (duration as f64);

        // 使用抛物线轨迹计算位置
        // 水平方向匀速运动
        let current_x = (start_x as f64 + distance_x * progress).round() as i32;

        // 垂直方向抛物线运动（开口向上，波峰向下）
        // y = apex_offset * (4*x^2 - 4*x) 形成开口向上的抛物线，谷点在 x=0.5 处
        let parabolic_factor = apex_offset * (4.0 * progress * progress - 4.0 * progress);
        let current_y = (start_y as f64 + distance_y * progress + parabolic_factor).round() as i32;

        // 更新窗口位置，使用 LogicalPosition
        if let Err(_e) = window.set_position(LogicalPosition::new(current_x as f64, current_y as f64)) {
            break;
        }

        // 短暂休眠以控制动画帧率
        tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
    }

    // 确保最终位置准确， 再次获取窗口大小和缩放因子
    let float_info = calculate_float_info_sync(app, page_type);
    let current_size_physical = window.outer_size().map_err(|e| format!("获取窗口大小失败: {}", e))?;
    let scale_factor = window.scale_factor().map_err(|e| format!("获取缩放因子失败: {}", e))?;
    let current_size = current_size_physical.to_logical::<i32>(scale_factor);
    let _ = window.set_size(LogicalSize::new(float_info.width as f64, float_info.height as f64));
    let end_x = screen_width - current_size.width;
    let end_y = screen_height - current_size.height - 120;

    if let Err(e) = window.set_position(LogicalPosition::new(end_x as f64, end_y as f64)) {
        return Err(format!("设置最终窗口位置失败: {}", e));
    }

    Ok(())
}
