use crate::{
    error::ErrorResponse,
    infra::middleware::{Language, UserId},
    repositories::user_repository::UserRepository,
    utils::{
        i18n::{message, ZH_CN},
        jwt::TokenType,
    },
    AppState,
};
use axum::{
    extract::{Request, State},
    middleware::Next,
    response::Response,
};
use jsonwebtoken::{decode, DecodingKey, Validation};
use serde::Deserialize;

#[derive(Deserialize)]
pub struct Claims {
    pub sub: String,
    #[allow(dead_code)]
    pub exp: usize,
    pub token_type: TokenType,
}

pub async fn auth_middleware(
    State(state): State<AppState>,
    mut req: Request,
    next: Next,
) -> Result<Response, ErrorResponse> {
    let language = req
        .extensions()
        .get::<Language>()
        .map(|v| v.0.as_str())
        .unwrap_or(ZH_CN);
    let header = req
        .headers()
        .get("Authorization")
        .and_then(|v| v.to_str().ok())
        .ok_or_else(|| {
            ErrorResponse::unauthorized(message(
                language,
                "缺少认证请求头",
                "Missing authorization header",
            ))
        })?;
    let token = header
        .strip_prefix("Bearer ")
        .filter(|v| !v.is_empty())
        .ok_or_else(|| {
            ErrorResponse::unauthorized(message(
                language,
                "认证格式无效",
                "Invalid authorization format",
            ))
        })?;
    let claims = decode::<Claims>(
        token,
        &DecodingKey::from_secret(state.config.auth.jwt_secret.as_bytes()),
        &Validation::default(),
    )
    .map_err(|_| {
        ErrorResponse::unauthorized(message(
            language,
            "令牌无效或已过期",
            "Token is invalid or expired",
        ))
    })?
    .claims;
    if claims.token_type != TokenType::Access {
        return Err(ErrorResponse::unauthorized(message(
            language,
            "令牌类型无效",
            "Invalid token type",
        )));
    }
    let user = UserRepository::new(state.pool.clone())
        .find_by_id_raw(&claims.sub)
        .await
        .map_err(|_| {
            ErrorResponse::internal(message(language, "验证用户失败", "Failed to verify user"))
        })?;
    let user = user.filter(|value| value.deleted_at.is_none());
    let Some(user) = user else {
        return Err(ErrorResponse::unauthorized(message(
            language,
            "用户不存在或已删除",
            "User not found or deleted",
        )));
    };
    if user.status != "active" {
        return Err(ErrorResponse::forbidden(message(
            language,
            "账号已被停用",
            "Account is not active",
        )));
    }
    req.extensions_mut().insert(UserId(claims.sub));
    Ok(next.run(req).await)
}
