use sqlx::{PgPool, postgres::PgPoolOptions, FromRow};
use std::env;
use std::error::Error;
use chrono::Utc;

// 从 models 模块引入 WeatherData 结构体
use crate::models::{User, WeatherData, WeatherDataBrief, WeatherListResponse};
use crate::error::AppError;

// 用于插入weather_data的数据
pub async fn insert_weather_data(pool: &PgPool, weather_data: &WeatherData, user_id: i32) -> Result<i32, AppError> {
    // 配额检查：非付费用户数据条数限制
    let user = get_user_by_id(pool, user_id).await?;
    let is_paid_active = user.is_paid && (user.paid_expires_at.is_none() || user.paid_expires_at.unwrap() > Utc::now());
    
    if !is_paid_active {
        let current_count = count_user_weather_data(pool, user_id).await?;
        let limit: i64 = env::var("FREE_USER_DATA_LIMIT")
            .unwrap_or_else(|_| "20".to_string())
            .parse()
            .unwrap_or(20);
        
        if current_count >= limit {
            return Err(AppError::Forbidden("数据条数已达上限，请升级为付费用户".to_string()));
        }
    }

    // 准备插入数据的 SQL 语句
    let insert_query = r#"
        INSERT INTO weather_data (
            user_id, title, date, hour, min, longitude, latitude, daysincejanfirst,
            theta, solardeclination, sunaltitude, overallcloudiness, lowcloudiness,
            cloudindex, solarradiationlevel, hasmeasuredwindspeed, measuredwindspeed,
            convertedwindspeed, pointheight, areatype, pointwindspeed,
            atmosphericstability, suitabilitydegree, winddirection, averagewinddirection,
            winddirectionstandarddeviation, windspeed, averagewindspeed, windspeedsuitability,
            winddirectionsuitability, overallsuitability, inspectiontype, assignmentnumber,
            calculatedwindspeed, hasspotcheckwindspeed, version, is_favorite
        ) VALUES (
            $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19,
            $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34, $35, $36, $37
        ) RETURNING id
    "#;

    // 3. 执行插入操作
    let inserted_id = match sqlx::query_as::<_, (i32,)>(insert_query)
        .bind(user_id)
        .bind(&weather_data.title)
        .bind(weather_data.date)
        .bind(weather_data.hours)
        .bind(weather_data.min)
        .bind(&weather_data.longitude)
        .bind(&weather_data.latitude)
        .bind(weather_data.day_since_jan_first)
        .bind(weather_data.theta)
        .bind(weather_data.solar_declination)
        .bind(weather_data.sun_altitude)
        .bind(&weather_data.overall_cloudiness)
        .bind(&weather_data.low_cloudiness)
        .bind(&weather_data.cloud_index)
        .bind(weather_data.solar_radiation_level)
        .bind(weather_data.has_measured_wind_speed)
        .bind(weather_data.measured_wind_speed) // <-- 修改: 直接绑定 Option<f64>
        .bind(weather_data.converted_wind_speed) // <-- 修改: 直接绑定 Option<i32>，并移除 `as i32`
        .bind(weather_data.point_height) // <-- 修改: 直接绑定 Option<f64>
        .bind(&weather_data.area_type)
        .bind(weather_data.point_wind_speed) // <-- 修改: 直接绑定 Option<f64>
        .bind(&weather_data.atmospheric_stability)
        .bind(&weather_data.suitability_degree)
        .bind(
            serde_json::to_value(&weather_data.wind_direction)
                .map_err(|e| AppError::Internal(format!("JSON 序列化失败: {}", e)))?,
        )
        .bind(weather_data.average_wind_direction)
        .bind(weather_data.wind_direction_standard_deviation)
        .bind(
            serde_json::to_value(&weather_data.wind_speed)
                .map_err(|e| AppError::Internal(format!("JSON 序列化失败: {}", e)))?,
        )
        .bind(weather_data.average_wind_speed)
        .bind(&weather_data.wind_speed_suitability)
        .bind(&weather_data.wind_direction_suitability)
        .bind(&weather_data.overall_suitability)
        .bind(&weather_data.inspection_type)
        .bind(&weather_data.assignment_number)
        .bind(weather_data.calculated_wind_speed) // 这个本来就是 Option，无需修改
        .bind(weather_data.has_spot_check_wind_speed)
        .bind(&weather_data.version)
        .bind(weather_data.is_favorite)
        .fetch_one(pool)
        .await
    {
        Ok((id,)) => id,
        Err(e) => {
            return Err(AppError::Database(format!("插入数据失败: {}", e)));
        }
    };

    // 4. 成功，返回插入的 ID
    Ok(inserted_id)
}

pub async fn create_pool() -> Result<PgPool, Box<dyn Error>> {
    // 获取数据库URL并提供友好错误信息
    let database_url =
        env::var("DATABASE_URL").map_err(|_| "环境变量DATABASE_URL未设置，请在.env文件中配置")?;

    // 配置连接池参数
    let pool = PgPoolOptions::new()
        .max_connections(20) // 根据应用需求调整最大连接数
        .acquire_timeout(std::time::Duration::from_secs(30)) // 获取连接的超时时间
        .connect(&database_url)
        .await
        .map_err(|e| format!("数据库连接失败: {}", e))?;

    Ok(pool)
}

// 获取天气数据详情
pub async fn get_weather_details(pool: &PgPool, weather_id: i32) -> Result<WeatherData, AppError> {
    let query = r#"
        SELECT
            wd.id, wd.title, wd.date, wd.hour, wd.min,
            wd.longitude, wd.latitude,
            wd.daysincejanfirst, wd.theta, wd.solardeclination,
            wd.sunaltitude, wd.overallcloudiness, wd.lowcloudiness,
            wd.cloudindex, wd.solarradiationlevel, wd.hasmeasuredwindspeed,
            wd.measuredwindspeed, wd.convertedwindspeed, wd.pointheight,
            wd.areatype, wd.pointwindspeed, wd.atmosphericstability,
            wd.suitabilitydegree, wd.winddirection, wd.averagewinddirection,
            wd.winddirectionstandarddeviation, wd.windspeed, wd.averagewindspeed,
            wd.windspeedsuitability, wd.winddirectionsuitability, wd.overallsuitability,
            wd.inspectiontype, wd.assignmentnumber, wd.calculatedwindspeed, wd.hasspotcheckwindspeed,
            wd.is_favorite, u.openid, wd.version
        FROM weather_data wd
        JOIN users u ON wd.user_id = u.id
        WHERE wd.id = $1
    "#;

    let row = match sqlx::query_as::<_, WeatherData>(query)
        .bind(weather_id)
        .fetch_optional(pool)
        .await
    {
        Ok(Some(row)) => row,
        Ok(None) => return Err(AppError::NotFound(format!("未找到ID为 {} 的天气数据", weather_id))),
        Err(e) => return Err(AppError::Database(format!("查询天气数据失败: {}", e))),
    };

    Ok(row)
}

// get_weather_list函数
pub async fn get_weather_list(
    pool: &PgPool,
    user_id: i32,
    page: i32,
    limit: i32,
) -> Result<WeatherListResponse, AppError> {
    let offset = (page - 1) * limit;

    // 1. 查询符合条件的总条数
    let total_query = r#"
        SELECT COUNT(*) as total 
        FROM weather_data 
        WHERE user_id = $1
    "#;
    let total = match sqlx::query_as::<_, (i64,)>(total_query)
        .bind(user_id)
        .fetch_one(pool)
        .await
    {
        Ok((count,)) => count,
        Err(e) => return Err(AppError::Database(format!("查询总条数失败: {}", e))),
    };

    // 2. 查询当前页数据列表
    let list_query = r#"
        SELECT 
            wd.id, wd.title, wd.date, wd.hour, wd.min, wd.longitude, wd.latitude, wd.is_favorite
        FROM weather_data wd
        WHERE wd.user_id = $1
        ORDER BY wd.date DESC, wd.hour DESC, wd.min DESC
        LIMIT $2 OFFSET $3
    "#;
    let list = match sqlx::query_as::<_, WeatherDataBrief>(list_query)
        .bind(user_id)
        .bind(limit)
        .bind(offset)
        .fetch_all(pool)
        .await
    {
        Ok(data) => data,
        Err(e) => return Err(AppError::Database(format!("查询天气数据列表失败: {}", e))),
    };

    // 3. 包装结果并返回
    Ok(WeatherListResponse { list, total })
}

pub async fn delete_weather_data(
    pool: &PgPool,
    weather_id: i32,
    user_id: i32,
) -> Result<(), AppError> {
    let query = r#"
        DELETE FROM weather_data 
        WHERE id = $1 AND user_id = $2
    "#;

    let result = sqlx::query(query)
        .bind(weather_id)
        .bind(user_id)
        .execute(pool)
        .await
        .map_err(|e| AppError::Database(format!("删除天气数据失败: {}", e)))?;

    if result.rows_affected() == 0 {
        return Err(AppError::NotFound(format!("未找到ID为 {} 的天气数据或无权限删除", weather_id)));
    }

    Ok(())
}

// 根据用户ID获取用户信息
pub async fn get_user_by_id(pool: &PgPool, user_id: i32) -> Result<User, AppError> {
    let query = r#"
        SELECT 
            id, name, openid, phone, type, "desc", is_paid, is_admin, paid_expires_at,
            avatar_url, nickname
        FROM users
        WHERE id = $1
    "#;

    let row = match sqlx::query_as::<_, User>(query)
        .bind(user_id)
        .fetch_optional(pool)
        .await
    {
        Ok(Some(row)) => row,
        Ok(None) => return Err(AppError::NotFound(format!("未找到ID为 {} 的用户", user_id))),
        Err(e) => return Err(AppError::Database(format!("查询用户信息失败: {}", e))),
    };

    Ok(row)
}

// 统计用户的天气数据条数
pub async fn count_user_weather_data(pool: &PgPool, user_id: i32) -> Result<i64, AppError> {
    let query = r#"
        SELECT COUNT(*) FROM weather_data WHERE user_id = $1
    "#;

    let count = match sqlx::query_as::<_, (i64,)>(query)
        .bind(user_id)
        .fetch_one(pool)
        .await
    {
        Ok((count,)) => count,
        Err(e) => return Err(AppError::Database(format!("查询天气数据条数失败: {}", e))),
    };

    Ok(count)
}

// 更新用户付费状态
pub async fn update_user_payment_status(
    pool: &PgPool,
    user_id: i32,
    is_paid: bool,
    paid_expires_at: Option<chrono::DateTime<chrono::Utc>>,
) -> Result<(), AppError> {
    let query = r#"
        UPDATE users 
        SET is_paid = $1, paid_expires_at = $2 
        WHERE id = $3
    "#;

    match sqlx::query(query)
        .bind(is_paid)
        .bind(paid_expires_at)
        .bind(user_id)
        .execute(pool)
        .await
    {
        Ok(_) => Ok(()),
        Err(e) => Err(AppError::Database(format!("更新用户付费状态失败: {}", e))),
    }
}

// 更新用户个人信息
pub async fn update_user_profile(
    pool: &PgPool,
    user_id: i32,
    nickname: &Option<String>,
    avatar_url: &Option<String>,
) -> Result<(), AppError> {
    let query = r#"
        UPDATE users 
        SET nickname = COALESCE($1, nickname),
            avatar_url = COALESCE($2, avatar_url)
        WHERE id = $3
    "#;

    match sqlx::query(query)
        .bind(nickname)
        .bind(avatar_url)
        .bind(user_id)
        .execute(pool)
        .await
    {
        Ok(_) => Ok(()),
        Err(e) => Err(AppError::Database(format!("更新用户个人信息失败: {}", e))),
    }
}

// ===== 支付系统 DB 函数 =====

/// 创建待支付订单
pub async fn get_user_orders(
    pool: &PgPool,
    user_id: i32,
) -> Result<Vec<crate::models::PaymentOrder>, AppError> {
    let rows = sqlx::query_as::<_, crate::models::PaymentOrder>(
        r#"
        SELECT id, user_id, order_no, package_type, amount, status, paid_at, expires_at, created_at
        FROM payment_orders
        WHERE user_id = $1
        ORDER BY created_at DESC
        "#,
    )
    .bind(user_id)
    .fetch_all(pool)
    .await
    .map_err(|e| AppError::Database(format!("查询订单失败: {}", e)))?;

    Ok(rows)
}

pub async fn create_payment_order(
    pool: &PgPool,
    user_id: i32,
    order_no: &str,
    package_type: &str,
    amount: i32,
    expires_at: Option<chrono::DateTime<chrono::Utc>>,
) -> Result<(), AppError> {
    let query = r#"
        INSERT INTO payment_orders (user_id, order_no, package_type, amount, expires_at)
        VALUES ($1, $2, $3, $4, $5)
    "#;

    sqlx::query(query)
        .bind(user_id)
        .bind(order_no)
        .bind(package_type)
        .bind(amount)
        .bind(expires_at)
        .execute(pool)
        .await
        .map_err(|e| AppError::Database(format!("创建订单失败: {}", e)))?;

    Ok(())
}

/// 确认订单支付（模拟）：更新订单状态 + 激活用户付费
///
/// 返回该订单的 expires_at（永久会员为 None）
/// 确认订单支付（模拟）：更新订单状态 + 激活用户付费（累加有效期）
///
/// 返回计算后的到期时间（永久会员返回 2099-12-31）
pub async fn confirm_payment_order(
    pool: &PgPool,
    order_no: &str,
    user_id: i32,
) -> Result<Option<chrono::DateTime<chrono::Utc>>, AppError> {
    // 检查订单有效
    let row = sqlx::query_as::<_, (i32, String)>(
        r#"SELECT user_id, status FROM payment_orders WHERE order_no = $1"#,
    )
    .bind(order_no)
    .fetch_optional(pool)
    .await
    .map_err(|e| AppError::Database(format!("查询订单失败: {}", e)))?;

    let (order_user_id, status) = match row {
        Some(r) => r,
        None => return Err(AppError::NotFound("订单不存在".to_string())),
    };

    if order_user_id != user_id {
        return Err(AppError::Forbidden("无权操作此订单".to_string()));
    }

    if status != "pending" {
        return Err(AppError::BadRequest("订单状态异常，无法确认支付".to_string()));
    }

    // 一次性完成：更新订单状态 + 累加计算新的到期时间（纯 SQL）
    let new_expires: Option<chrono::DateTime<chrono::Utc>> = sqlx::query_scalar(
        r#"
        WITH updated_order AS (
            UPDATE payment_orders SET status = 'paid', paid_at = NOW() WHERE order_no = $1 RETURNING package_type
        )
        UPDATE users SET
            is_paid = true,
            paid_expires_at =
                CASE
                    WHEN uo.package_type = 'permanent' THEN '2099-12-31 23:59:59+00'::timestamptz
                    ELSE GREATEST(COALESCE(users.paid_expires_at, NOW()), NOW()) +
                        CASE
                            WHEN uo.package_type = 'monthly' THEN INTERVAL '30 days'
                            WHEN uo.package_type = 'yearly' THEN INTERVAL '365 days'
                            ELSE INTERVAL '0 days'
                        END
                END
        FROM updated_order uo
        WHERE users.id = $2
        RETURNING users.paid_expires_at
        "#,
    )
    .bind(order_no)
    .bind(user_id)
    .fetch_one(pool)
    .await
    .map_err(|e| AppError::Database(format!("支付确认失败: {}", e)))?;

    Ok(new_expires)
}

/// 确认订单支付（支付宝异步回调用，通过 order_no 查找，不校验 user_id）
pub async fn confirm_payment_order_by_orderno(
    pool: &PgPool,
    order_no: &str,
) -> Result<(), AppError> {
    // 检查订单有效
    let status: Option<String> = sqlx::query_scalar(
        r#"SELECT status FROM payment_orders WHERE order_no = $1"#,
    )
    .bind(order_no)
    .fetch_optional(pool)
    .await
    .map_err(|e| AppError::Database(format!("查询订单失败: {}", e)))?;

    let status = match status {
        Some(s) => s,
        None => return Err(AppError::NotFound("订单不存在".to_string())),
    };

    if status != "pending" {
        return Ok(());
    }

    // 一次性完成：更新订单状态 + 累加计算新的到期时间
    sqlx::query(
        r#"
        WITH updated_order AS (
            UPDATE payment_orders SET status = 'paid', paid_at = NOW() WHERE order_no = $1 RETURNING package_type, user_id
        )
        UPDATE users SET
            is_paid = true,
            paid_expires_at =
                CASE
                    WHEN uo.package_type = 'permanent' THEN '2099-12-31 23:59:59+00'::timestamptz
                    ELSE GREATEST(COALESCE(users.paid_expires_at, NOW()), NOW()) +
                        CASE
                            WHEN uo.package_type = 'monthly' THEN INTERVAL '30 days'
                            WHEN uo.package_type = 'yearly' THEN INTERVAL '365 days'
                            ELSE INTERVAL '0 days'
                        END
                END
        FROM updated_order uo
        WHERE users.id = uo.user_id
        "#,
    )
    .bind(order_no)
    .execute(pool)
    .await
    .map_err(|e| AppError::Database(format!("支付确认失败: {}", e)))?;

    Ok(())
}

/// 获取用户配额信息
///
/// 返回 (已用条数, 是否付费活跃, 到期时间)
pub async fn get_user_quota(
    pool: &PgPool,
    user_id: i32,
) -> Result<(i64, bool, Option<chrono::DateTime<chrono::Utc>>), AppError> {
    let user = get_user_by_id(pool, user_id).await?;
    let is_paid_active = user.is_paid
        && (user.paid_expires_at.is_none()
            || user.paid_expires_at.unwrap() > chrono::Utc::now());
    let used = count_user_weather_data(pool, user_id).await?;
    Ok((used, is_paid_active, user.paid_expires_at))
}

// ===== 收藏功能 DB 函数 =====

/// 获取收藏列表（分页）
pub async fn get_favorites_list(
    pool: &PgPool,
    user_id: i32,
    page: i32,
    limit: i32,
) -> Result<WeatherListResponse, AppError> {
    let offset = (page - 1) * limit;

    let total_query = r#"
        SELECT COUNT(*) as total
        FROM weather_data
        WHERE user_id = $1 AND is_favorite = true
    "#;
    let total = sqlx::query_as::<_, (i64,)>(total_query)
        .bind(user_id)
        .fetch_one(pool)
        .await
        .map_err(|e| AppError::Database(format!("查询收藏总数失败: {}", e)))?
        .0;

    let list_query = r#"
        SELECT
            id, title, date, hour, min, longitude, latitude, is_favorite
        FROM weather_data
        WHERE user_id = $1 AND is_favorite = true
        ORDER BY date DESC, hour DESC, min DESC
        LIMIT $2 OFFSET $3
    "#;
    let list = sqlx::query_as::<_, WeatherDataBrief>(list_query)
        .bind(user_id)
        .bind(limit)
        .bind(offset)
        .fetch_all(pool)
        .await
        .map_err(|e| AppError::Database(format!("查询收藏列表失败: {}", e)))?;

    Ok(WeatherListResponse { list, total })
}

/// 设置天气数据的收藏状态
pub async fn set_weather_favorite(
    pool: &PgPool,
    weather_id: i32,
    user_id: i32,
    is_favorite: bool,
) -> Result<(), AppError> {
    let query = r#"
        UPDATE weather_data
        SET is_favorite = $1
        WHERE id = $2 AND user_id = $3
    "#;

    let result = sqlx::query(query)
        .bind(is_favorite)
        .bind(weather_id)
        .bind(user_id)
        .execute(pool)
        .await
        .map_err(|e| AppError::Database(format!("更新收藏状态失败: {}", e)))?;

    if result.rows_affected() == 0 {
        return Err(AppError::NotFound(format!("未找到ID为 {} 的天气数据或无权限修改", weather_id)));
    }

    Ok(())
}

// ===== Refresh Token DB 函数 =====

#[derive(Debug, FromRow)]
pub struct RefreshToken {
    pub id: i32,
    pub user_id: i32,
    pub token: String,
    pub expires_at: chrono::DateTime<chrono::Utc>,
    pub created_at: chrono::DateTime<chrono::Utc>,
}

pub async fn create_refresh_token(
    pool: &PgPool,
    user_id: i32,
    token: &str,
    expires_at: chrono::DateTime<chrono::Utc>,
) -> Result<(), AppError> {
    let query = r#"
        INSERT INTO refresh_tokens (user_id, token, expires_at)
        VALUES ($1, $2, $3)
    "#;

    sqlx::query(query)
        .bind(user_id)
        .bind(token)
        .bind(expires_at)
        .execute(pool)
        .await
        .map_err(|e| AppError::Database(format!("创建 refresh_token 失败: {}", e)))?;

    Ok(())
}

pub async fn verify_refresh_token(
    pool: &PgPool,
    token: &str,
) -> Result<RefreshToken, AppError> {
    let query = r#"
        SELECT id, user_id, token, expires_at, created_at
        FROM refresh_tokens
        WHERE token = $1 AND expires_at > NOW()
    "#;

    sqlx::query_as::<_, RefreshToken>(query)
        .bind(token)
        .fetch_optional(pool)
        .await
        .map_err(|e| AppError::Database(format!("验证 refresh_token 失败: {}", e)))?
        .ok_or_else(|| AppError::Unauthorized("Refresh token 无效或已过期".to_string()))
}

pub async fn delete_refresh_token(pool: &PgPool, user_id: i32) -> Result<(), AppError> {
    let query = r#"DELETE FROM refresh_tokens WHERE user_id = $1"#;

    sqlx::query(query)
        .bind(user_id)
        .execute(pool)
        .await
        .map_err(|e| AppError::Database(format!("删除 refresh_token 失败: {}", e)))?;

    Ok(())
}

pub async fn delete_specific_refresh_token(pool: &PgPool, token: &str) -> Result<(), AppError> {
    let query = r#"DELETE FROM refresh_tokens WHERE token = $1"#;

    sqlx::query(query)
        .bind(token)
        .execute(pool)
        .await
        .map_err(|e| AppError::Database(format!("删除 refresh_token 失败: {}", e)))?;

    Ok(())
}

pub async fn cleanup_expired_refresh_tokens(pool: &PgPool) -> Result<u64, AppError> {
    let query = r#"DELETE FROM refresh_tokens WHERE expires_at <= NOW()"#;

    let result = sqlx::query(query)
        .execute(pool)
        .await
        .map_err(|e| AppError::Database(format!("清理过期 refresh_token 失败: {}", e)))?;

    Ok(result.rows_affected())
}
