// src/auth/jwt.rs
use jsonwebtoken::{encode, decode, Header, EncodingKey, DecodingKey, Validation};
use serde::{Deserialize, Serialize};
use time::{Duration, OffsetDateTime};
use uuid::Uuid;
use std::sync::OnceLock;
use crate::auth::models::AuthError;

static KEYS: OnceLock<Keys> = OnceLock::new();

struct Keys {
    encoding: EncodingKey,
    decoding: DecodingKey,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Claims {
    pub sub: Uuid,    // User ID
    pub exp: i64,     // Expiration time
    pub role: String, // User role
    pub username: String,
}

pub fn init_jwt() -> Result<(), AuthError> {
    let secret = std::env::var("JWT_SECRET")
        .map_err(|_| AuthError::ConfigError("JWT_SECRET must be set".to_string()))?;

    KEYS.set(Keys {
        encoding: EncodingKey::from_secret(secret.as_bytes()),
        decoding: DecodingKey::from_secret(secret.as_bytes()),
    }).map_err(|_| AuthError::ConfigError("Failed to initialize JWT keys".to_string()))?;

    Ok(())
}

pub fn generate_token(user_id: Uuid, role: &str, username: &str) -> Result<String, AuthError> {
    let keys = KEYS.get().ok_or(AuthError::ConfigError("JWT not initialized".to_string()))?;
    
    let exp = OffsetDateTime::now_utc() + Duration::days(365000);
    let claims = Claims {
        sub: user_id,
        exp: exp.unix_timestamp(),
        role: role.to_string(),
        username: username.to_string(),
    };

    encode(&Header::default(), &claims, &keys.encoding)
        .map_err(|e| AuthError::JwtError(e.to_string()))
}

pub fn validate_token(token: &str) -> Result<Claims, AuthError> {
    let keys = KEYS.get().ok_or(AuthError::ConfigError("JWT not initialized".to_string()))?;
    
    decode::<Claims>(token, &keys.decoding, &Validation::default())
        .map(|data| data.claims)
        .map_err(|e| AuthError::JwtError(e.to_string()))
}
