use actix_web::{web, delete, get, post, HttpRequest, HttpResponse};
use sqlx::postgres::PgPool;
use tracing::{debug, info};

use crate::auth;
use crate::db;
use crate::error::AppError;
use crate::handlers::TEMPLATES_DIR;
use crate::models::{AppState, Claims};

#[post("/api/post-weather-data")]
pub async fn post_weather_data(
    data: web::Json<crate::models::WeatherData>,
    pool: web::Data<PgPool>,
    claims: web::ReqData<Claims>,
) -> Result<HttpResponse, AppError> {
    info!("Received weather data, preparing to insert into DB...");

    let user_id = claims.user_id;

    // 调用 db.rs 中的函数来处理数据库逻辑
    let inserted_id = db::insert_weather_data(pool.get_ref(), &data, user_id).await?;
    info!(
        "Successfully inserted weather data with id: {}",
        inserted_id
    );
    Ok(HttpResponse::Ok().json(serde_json::json!({
        "success": true,
        "message": "Weather data inserted successfully",
        "inserted_id": inserted_id,
        "received_assignment": data.assignment_number
    })))
}

#[post("/api/generate-temp-token/{resource_id}")]
pub async fn generate_temp_token_handler(
    path: web::Path<i32>,
    pool: web::Data<PgPool>,
    claims: web::ReqData<Claims>,
    app_state: web::Data<AppState>,
) -> Result<HttpResponse, AppError> {
    let resource_id = path.into_inner();
    let openid: &String = &claims.openid;

    let weather_data = db::get_weather_details(pool.get_ref(), resource_id).await?;
    if weather_data.openid != *openid {
        return Err(AppError::Forbidden("无权限为该资源生成临时token".to_string()));
    }

    let temp_token = auth::generate_temp_token(openid, resource_id, &app_state.jwt_secret, 10)
        .map_err(|e| AppError::Internal(format!("生成临时token失败: {}", e)))?;

    Ok(HttpResponse::Ok().json(serde_json::json!({
        "success": true,
        "temp_token": temp_token,
        "expire_minutes": 10,
    })))
}

#[get("/weather/details")]
pub async fn get_weather_details(
    pool: web::Data<PgPool>,
    req: HttpRequest,
    query: web::Query<serde_json::Value>,
    app_state: web::Data<AppState>,
) -> Result<HttpResponse, AppError> {
    let mut is_temp_token = false;

    // 从 Authorization header 中提取并验证 JWT（自己处理，不依赖 middleware）
    let claims_from_header = || -> Option<Claims> {
        let auth_header = req.headers().get("Authorization")?;
        let auth_str = auth_header.to_str().ok()?;
        let token = auth_str.strip_prefix("Bearer ")?;
        let jwt_secret = &app_state.jwt_secret;
        auth::verify_token(token, jwt_secret).ok()
    };

    let (openid, weather_id) =
        if let Some(temp_token) = query.get("temp_token").and_then(|v| v.as_str()) {
            is_temp_token = true;
            let temp_claims = auth::verify_temp_token(temp_token, &app_state.jwt_secret)
                .map_err(|e| AppError::Unauthorized(format!("临时token无效: {}", e)))?;
            (temp_claims.openid, temp_claims.resource_id)
        } else if let Some(claims) = claims_from_header() {
            let weather_id = match query.get("id") {
                Some(v) if v.is_i64() => v.as_i64().unwrap() as i32,
                Some(v) if v.is_string() => {
                    v.as_str().and_then(|s| s.parse::<i32>().ok()).unwrap_or(0)
                }
                Some(v) if v.is_number() => v.as_f64().unwrap() as i32,
                _ => {
                    return Err(AppError::BadRequest("缺少资源ID参数（id）".to_string()));
                }
            };
            (claims.openid.clone(), weather_id)
        } else {
            return Err(AppError::Unauthorized("缺少token（需提供JWT或临时token）".to_string()));
        };

    let weather_data = db::get_weather_details(pool.get_ref(), weather_id).await?;
    if weather_data.openid != openid {
        return Err(AppError::Forbidden("无权限访问该数据".to_string()));
    }

    if is_temp_token {
        let index_html = match TEMPLATES_DIR.get_file("index.html") {
            Some(file) => file.contents_utf8().unwrap_or_default(),
            None => {
                return Err(AppError::Internal("无法找到模板文件".to_string()));
            }
        };

        let weather_data_json = serde_json::to_string(&weather_data).unwrap_or_default();
        let data_script = format!(
            r#"
        <script>
            window.weatherData = {};
        </script>
        "#,
            weather_data_json
        );

        let rendered_html = index_html
            .replace("<!-- 详细信息将在这里显示 -->", &data_script)
            .replace(
                "style=\"display: none;\"",
                "",
            );

        Ok(HttpResponse::Ok()
            .content_type("text/html; charset=utf-8")
            .body(rendered_html))
    } else {
        Ok(HttpResponse::Ok().json(serde_json::json!({
            "success": true,
            "data": weather_data
        })))
    }
}

#[get("/weather")]
pub async fn get_weather_brief(
    query: web::Query<serde_json::Value>,
    pool: web::Data<PgPool>,
    claims: web::ReqData<Claims>,
) -> Result<HttpResponse, AppError> {
    let page = match query.get("page") {
        Some(v) => {
            let raw = if let Some(num) = v.as_i64() {
                num as i32
            } else if let Some(s) = v.as_str() {
                s.parse().unwrap_or(1)
            } else {
                1
            };
            raw.max(1)
        }
        None => 1,
    };

    let limit = match query.get("limit") {
        Some(v) => {
            let raw = if let Some(num) = v.as_i64() {
                num as i32
            } else if let Some(s) = v.as_str() {
                s.parse().unwrap_or(10)
            } else {
                10
            };
            raw.clamp(1, 100)
        }
        None => 10,
    };

    debug!("获取天气数据列表, 页码: {}, 每页条数: {}", page, limit);

    let response = db::get_weather_list(pool.get_ref(), claims.user_id, page, limit).await?;
    debug!(
        "获取到的天气列表: {:?}, 总条数: {}",
        response.list, response.total
    );
    Ok(HttpResponse::Ok().json(serde_json::json!({
        "success": true,
        "data": response.list,
        "page": page,
        "limit": limit,
        "total": response.total
    })))
}

#[delete("/weather/delete/{id}")]
pub async fn delete_weather(
    path: web::Path<i32>,
    pool: web::Data<PgPool>,
    claims: web::ReqData<Claims>,
) -> Result<HttpResponse, AppError> {
    let weather_id = path.into_inner();
    info!("删除天气数据, ID: {}", weather_id);

    db::delete_weather_data(pool.get_ref(), weather_id, claims.user_id).await?;
    Ok(HttpResponse::Ok().json(serde_json::json!({
        "success": true,
        "message": format!("天气数据 {} 已成功删除", weather_id)
    })))
}
