use erp_core::crypto::PiiCrypto;
use erp_core::events::EventBus;
use sea_orm::DatabaseConnection;
use uuid::Uuid;

/// Auth-specific state extracted from the server's AppState via `FromRef`.
///
/// This avoids a circular dependency between erp-auth and erp-server.
/// The server crate implements `FromRef<AppState> for AuthState` so that
/// Axum handlers in erp-auth can extract `State<AuthState>` directly.
///
/// Contains everything the auth handlers need:
/// - Database connection for user/credential lookups
/// - EventBus for publishing domain events
/// - JWT configuration for token signing and validation
/// - Default tenant ID for the bootstrap phase
#[derive(Clone)]
pub struct AuthState {
    pub db: DatabaseConnection,
    pub event_bus: EventBus,
    pub jwt_secret: String,
    pub access_ttl_secs: i64,
    pub refresh_ttl_secs: i64,
    pub default_tenant_id: Uuid,
    pub redis: Option<redis::Client>,
    pub crypto: PiiCrypto,
}

/// Parse a human-readable TTL string (e.g. "15m", "7d", "1h", "900s") into seconds.
///
/// Falls back to parsing the raw string as seconds if no unit suffix is recognized.
pub fn parse_ttl(ttl: &str) -> i64 {
    let ttl = ttl.trim();
    if let Some(num) = ttl.strip_suffix('s') {
        num.parse::<i64>().unwrap_or(900)
    } else if let Some(num) = ttl.strip_suffix('m') {
        num.parse::<i64>().map(|n| n * 60).unwrap_or(900)
    } else if let Some(num) = ttl.strip_suffix('h') {
        num.parse::<i64>().map(|n| n * 3600).unwrap_or(900)
    } else if let Some(num) = ttl.strip_suffix('d') {
        num.parse::<i64>().map(|n| n * 86400).unwrap_or(900)
    } else {
        ttl.parse::<i64>().unwrap_or(900)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parse_ttl_seconds() {
        assert_eq!(parse_ttl("900s"), 900);
    }

    #[test]
    fn parse_ttl_minutes() {
        assert_eq!(parse_ttl("15m"), 900);
    }

    #[test]
    fn parse_ttl_hours() {
        assert_eq!(parse_ttl("1h"), 3600);
    }

    #[test]
    fn parse_ttl_days() {
        assert_eq!(parse_ttl("7d"), 604800);
    }

    #[test]
    fn parse_ttl_raw_number() {
        assert_eq!(parse_ttl("300"), 300);
    }

    #[test]
    fn parse_ttl_fallback_on_invalid() {
        assert_eq!(parse_ttl("invalid"), 900);
    }
}
