//! 认证处理器

use axum::{
    extract::State,
    http::StatusCode,
    response::IntoResponse,
    Json,
};
use std::sync::Arc;

use crate::models::{
    ApiResponse, AuthResponse, LoginRequest, RegisterRequest,
};
use crate::services::{
    auth::{AuthService, UserRepository},
    device::DeviceRepository,
    AppState,
};
use super::{api_error, AuthUser};

/// 用户注册
pub async fn register(
    State(state): State<Arc<AppState>>,
    Json(req): Json<RegisterRequest>,
) -> impl IntoResponse {
    // 验证输入
    if req.username.len() < 3 || req.username.len() > 50 {
        return api_error(StatusCode::BAD_REQUEST, "用户名长度必须在3-50之间");
    }
    if req.password.len() < 6 {
        return api_error(StatusCode::BAD_REQUEST, "密码长度至少6位");
    }

    let repo = UserRepository::new(&state.db);

    // 检查用户名是否已存在
    if let Ok(Some(_)) = repo.find_by_username(&req.username).await {
        return api_error(StatusCode::CONFLICT, "用户名已存在");
    }

    // 哈希密码
    let (hash, salt) = AuthService::hash_password(&req.password);

    // 创建用户
    match repo.create(&req.username, &hash, &salt, req.email.as_deref()).await {
        Ok(user) => {
            let auth_service = AuthService::new(&state.config);
            match auth_service.generate_token(&user) {
                Ok(token) => (
                    StatusCode::CREATED,
                    Json(ApiResponse::ok(AuthResponse {
                        token,
                        user: user.into(),
                    })),
                )
                    .into_response(),
                Err(e) => api_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
            }
        }
        Err(e) => api_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
    }
}

/// 用户登录
pub async fn login(
    State(state): State<Arc<AppState>>,
    Json(req): Json<LoginRequest>,
) -> impl IntoResponse {
    let repo = UserRepository::new(&state.db);

    // 查找用户
    let user = match repo.find_by_username(&req.username).await {
        Ok(Some(user)) => user,
        Ok(None) => return api_error(StatusCode::UNAUTHORIZED, "用户名或密码错误"),
        Err(e) => return api_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
    };

    // 验证密码
    if !AuthService::verify_password(&req.password, &user.password_hash) {
        return api_error(StatusCode::UNAUTHORIZED, "用户名或密码错误");
    }

    // 更新最后登录时间
    let _ = repo.update_last_login(&user.id).await;

    // 如果提供了设备ID，绑定设备到用户
    if let Some(device_id) = &req.device_id {
        let device_repo = DeviceRepository::new(&state.db);
        let _ = device_repo.bind_to_user(device_id, &user.id).await;
    }

    // 生成令牌
    let auth_service = AuthService::new(&state.config);
    match auth_service.generate_token(&user) {
        Ok(token) => (
            StatusCode::OK,
            Json(ApiResponse::ok(AuthResponse {
                token,
                user: user.into(),
            })),
        )
            .into_response(),
        Err(e) => api_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
    }
}

/// 退出登录
pub async fn logout(
    State(_state): State<Arc<AppState>>,
    _user: AuthUser,
) -> impl IntoResponse {
    // JWT 是无状态的，客户端只需删除本地令牌
    // 如果需要服务端失效令牌，可以使用令牌黑名单
    (StatusCode::OK, Json(ApiResponse::ok("已退出登录"))).into_response()
}

/// 刷新令牌
pub async fn refresh_token(
    State(state): State<Arc<AppState>>,
    user: AuthUser,
) -> impl IntoResponse {
    let repo = UserRepository::new(&state.db);

    match repo.find_by_id(&user.user_id).await {
        Ok(user_row) => {
            let auth_service = AuthService::new(&state.config);
            match auth_service.generate_token(&user_row) {
                Ok(token) => (
                    StatusCode::OK,
                    Json(ApiResponse::ok(AuthResponse {
                        token,
                        user: user_row.into(),
                    })),
                )
                    .into_response(),
                Err(e) => api_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
            }
        }
        Err(e) => api_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
    }
}
