use std::time::Duration;
use serde::{Deserialize, Serialize};
use anyhow::Result;

#[derive(Clone)]
pub struct AppState {
    pub db: crate::db::MongoDb,
    pub jwt_service: crate::auth::JwtService,
    pub config: Config,
    pub audit_logger: Option<crate::security::AuditLogger>,
    pub session_manager: Option<crate::security::SessionManager>,
    pub account_lockout: Option<crate::security::AccountLockout>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
    pub server: ServerConfig,
    pub database: DatabaseConfig,
    pub jwt: JwtConfig,
    pub encryption: EncryptionConfig,
    pub cors: CorsConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerConfig {
    pub host: String,
    pub port: u16,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DatabaseConfig {
    pub uri: String,
    pub database: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JwtConfig {
    pub secret: String,
    pub access_token_expiry_minutes: i64,
    pub refresh_token_expiry_days: i64,
}

impl JwtConfig {
    pub fn access_token_expiry_duration(&self) -> Duration {
        Duration::from_secs(self.access_token_expiry_minutes as u64 * 60)
    }
    
    pub fn refresh_token_expiry_duration(&self) -> Duration {
        Duration::from_secs(self.refresh_token_expiry_days as u64 * 86400)
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EncryptionConfig {
    pub algorithm: String,
    pub key_length: usize,
    pub pbkdf2_iterations: u32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CorsConfig {
    pub allowed_origins: Vec<String>,
}

impl Config {
    pub fn from_env() -> Result<Self> {
        dotenv::dotenv().ok();
        
        let server_host = std::env::var("SERVER_HOST")
            .unwrap_or_else(|_| "0.0.0.0".to_string());
        let server_port = std::env::var("SERVER_PORT")
            .unwrap_or_else(|_| "8000".to_string())
            .parse::<u16>()?;
        
        let mongodb_uri = std::env::var("MONGODB_URI")
            .unwrap_or_else(|_| "mongodb://localhost:27017".to_string());
        let mongodb_database = std::env::var("MONGODB_DATABASE")
            .unwrap_or_else(|_| "normogen".to_string());
        
        let jwt_secret = std::env::var("JWT_SECRET")
            .expect("JWT_SECRET must be set");
        let access_token_expiry = std::env::var("JWT_ACCESS_TOKEN_EXPIRY_MINUTES")
            .unwrap_or_else(|_| "15".to_string())
            .parse::<i64>()?;
        let refresh_token_expiry = std::env::var("JWT_REFRESH_TOKEN_EXPIRY_DAYS")
            .unwrap_or_else(|_| "30".to_string())
            .parse::<i64>()?;
        
        let cors_origins = std::env::var("CORS_ALLOWED_ORIGINS")
            .unwrap_or_else(|_| "http://localhost:3000,http://localhost:6001".to_string())
            .split(',')
            .map(|s| s.trim().to_string())
            .collect();
        
        Ok(Config {
            server: ServerConfig {
                host: server_host,
                port: server_port,
            },
            database: DatabaseConfig {
                uri: mongodb_uri,
                database: mongodb_database,
            },
            jwt: JwtConfig {
                secret: jwt_secret,
                access_token_expiry_minutes: access_token_expiry,
                refresh_token_expiry_days: refresh_token_expiry,
            },
            encryption: EncryptionConfig {
                algorithm: "aes-256-gcm".to_string(),
                key_length: 32,
                pbkdf2_iterations: 100000,
            },
            cors: CorsConfig {
                allowed_origins: cors_origins,
            },
        })
    }
}
