// [TSM.ID].[11031972] — All Rights Reserved. Proprietary & Confidential.
use axum::{
    extract::Request,
    middleware::Next,
    response::Response,
    http::StatusCode,
};
use jsonwebtoken::{decode, DecodingKey, Validation, Algorithm};
use serde::{Deserialize, Serialize};
use tracing::warn;
use std::sync::OnceLock;

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct IamClaims {
    pub sub: String,         // User/Tenant ID
    pub role: String,        // "supreme_admin" or "tenant"
    pub packages: Vec<String>, // ["phase-1", "phase-72", "billing"]
    pub exp: usize,
}

/// JWT Secret WAJIB dari environment variable — DILARANG HARDCODE
/// Env: XCU_IAM_SECRET (harus sama dengan secret JUMPA.ID IAM)
static IAM_SECRET: OnceLock<String> = OnceLock::new();

fn get_iam_secret() -> &'static str {
    IAM_SECRET.get_or_init(|| {
        std::env::var("XCU_IAM_SECRET").unwrap_or_else(|_| {
            warn!("[IAM] ⚠️ XCU_IAM_SECRET env var NOT SET! Using fallback. SET THIS IN PRODUCTION!");
            "XCU_IAM_SECRET_NOT_CONFIGURED".to_string()
        })
    })
}

pub async fn xcu_gatekeeper(
    mut req: Request,
    next: Next,
) -> Result<Response, StatusCode> {
    // 1. Ekstrak Token dari Header atau Query Params (untuk SSE)
    let auth_header = req.headers().get("Authorization").and_then(|h| h.to_str().ok());
    
    let token = if let Some(auth) = auth_header {
        if auth.starts_with("Bearer ") {
            Some(auth.trim_start_matches("Bearer "))
        } else {
            None
        }
    } else {
        // Fallback ke query param (misal untuk SSE)
        req.uri().query().and_then(|q| {
            q.split('&').find(|kv| kv.starts_with("token=")).map(|kv| kv.trim_start_matches("token="))
        })
    };

    if let Some(t) = token {
        let validation = Validation::new(Algorithm::HS256);
        // validate_exp = true (default) — expired tokens WAJIB ditolak
        
        match decode::<IamClaims>(
            t,
            &DecodingKey::from_secret(get_iam_secret().as_bytes()),
            &validation,
        ) {
            Ok(token_data) => {
                // Token Sah! Masukkan Identitas Lintas-Dimensi ke dalam mesin.
                req.extensions_mut().insert(token_data.claims);
            }
            Err(e) => {
                warn!("IAM Matrix Breach Detected: Invalid JWT Token. {:?}", e);
                return Err(StatusCode::UNAUTHORIZED);
            }
        }
    } else {
        // TANPA TOKEN = REJECTED. Tidak ada guest bypass.
        warn!("[IAM] No token provided — ACCESS DENIED");
        return Err(StatusCode::UNAUTHORIZED);
    }

    Ok(next.run(req).await)
}
