mod auth;
mod config;
mod db;
mod handlers;
mod middleware;
mod models;
mod security;
mod services;

use axum::{
    routing::{delete, get, post, put},
    Router,
};
use config::Config;
use std::sync::Arc;
use tower::ServiceBuilder;
use tower_http::{cors::CorsLayer, trace::TraceLayer};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    eprintln!("NORMOGEN BACKEND STARTING...");
    eprintln!("Loading environment variables...");

    match dotenv::dotenv() {
        Ok(path) => eprintln!("Loaded .env from: {:?}", path),
        Err(e) => eprintln!("No .env file found (this is OK in Docker): {}", e),
    }

    eprintln!("Initializing logging...");
    tracing_subscriber::fmt::init();

    tracing::info!("Starting Normogen backend server");

    // Load configuration
    let config = Config::from_env()?;
    eprintln!("Configuration loaded successfully");

    // Connect to MongoDB
    tracing::info!("Connecting to MongoDB at {}", config.database.uri);
    eprintln!("Connecting to MongoDB...");
    let db = match db::MongoDb::new(&config.database.uri, &config.database.database).await {
        Ok(db) => {
            tracing::info!(
                "Connected to MongoDB database: {}",
                config.database.database
            );
            eprintln!("MongoDB connection successful");
            db
        }
        Err(e) => {
            eprintln!("FATAL: Failed to connect to MongoDB: {}", e);
            return Err(e);
        }
    };

    match db.health_check().await {
        Ok(_) => {
            tracing::info!("MongoDB health check: OK");
            eprintln!("MongoDB health check: OK");
        }
        Err(e) => {
            tracing::warn!("MongoDB health check failed: {}", e);
            eprintln!("WARNING: MongoDB health check failed: {}", e);
        }
    }

    // Create JWT service
    let jwt_service = auth::JwtService::new(config.jwt.clone());

    // Get the underlying MongoDB database for security services
    let database = db.get_database();

    // Initialize security services (Phase 2.6)
    let audit_logger = security::AuditLogger::new(&database);
    let session_manager = security::SessionManager::new(&database);

    // Create account lockout service with reasonable defaults
    let user_collection = database.collection("users");
    let account_lockout = security::AccountLockout::new(
        user_collection,
        5,    // max_attempts
        15,   // base_duration_minutes
        1440, // max_duration_minutes (24 hours)
    );

    // Initialize health stats repository (Phase 2.7) - using Database pattern
    let health_stats_repo = models::health_stats::HealthStatisticsRepository::new(&database);

    // Initialize interaction service (Phase 2.8)
    let interaction_service = Arc::new(services::InteractionService::new());
    eprintln!("Interaction service initialized (Phase 2.8)");

    // Create application state
    let state = config::AppState {
        db,
        jwt_service,
        config: config.clone(),
        audit_logger: Some(audit_logger),
        session_manager: Some(session_manager),
        account_lockout: Some(account_lockout),
        health_stats_repo: Some(health_stats_repo),
        mongo_client: None,
        interaction_service: Some(interaction_service),
    };

    eprintln!("Building router with security middleware...");

    // Build public routes (no auth required)
    let public_routes = Router::new()
        .route(
            "/health",
            get(handlers::health_check).head(handlers::health_check),
        )
        .route("/ready", get(handlers::ready_check))
        .route("/api/auth/register", post(handlers::register))
        .route("/api/auth/login", post(handlers::login))
        .route(
            "/api/auth/recover-password",
            post(handlers::recover_password),
        );

    // Build protected routes (auth required)
    let protected_routes = Router::new()
        // User profile management
        .route("/api/users/me", get(handlers::get_profile))
        .route("/api/users/me", put(handlers::update_profile))
        .route("/api/users/me", delete(handlers::delete_account))
        .route("/api/users/me/change-password", post(handlers::change_password))

        // User settings
        .route("/api/users/me/settings", get(handlers::get_settings))
        .route("/api/users/me/settings", put(handlers::update_settings))

        // Share management
        .route("/api/shares", post(handlers::create_share))
        .route("/api/shares", get(handlers::list_shares))
        .route("/api/shares/:id", put(handlers::update_share))
        .route("/api/shares/:id", delete(handlers::delete_share))

        // Permission checking
        .route("/api/permissions/check", post(handlers::check_permission))

        // Session management (Phase 2.6)
        .route("/api/sessions", get(handlers::get_sessions))
        .route("/api/sessions/:id", delete(handlers::revoke_session))
        .route("/api/sessions/all", delete(handlers::revoke_all_sessions))

        // Medication management (Phase 2.7)
        .route("/api/medications", post(handlers::create_medication))
        .route("/api/medications", get(handlers::list_medications))
        .route("/api/medications/:id", get(handlers::get_medication))
        .route("/api/medications/:id", post(handlers::update_medication))
        .route("/api/medications/:id/delete", post(handlers::delete_medication))
        .route("/api/medications/:id/log", post(handlers::log_dose))
        .route("/api/medications/:id/adherence", get(handlers::get_adherence))

        // Health statistics management (Phase 2.7)
        .route("/api/health-stats", post(handlers::create_health_stat))
        .route("/api/health-stats", get(handlers::list_health_stats))
        .route("/api/health-stats/trends", get(handlers::get_health_trends))
        .route("/api/health-stats/:id", get(handlers::get_health_stat))
        .route("/api/health-stats/:id", put(handlers::update_health_stat))
        .route("/api/health-stats/:id", delete(handlers::delete_health_stat))

        // Drug interactions (Phase 2.8)
        .route("/api/interactions/check", post(handlers::check_interactions))
        .route("/api/interactions/check-new", post(handlers::check_new_medication))
        .layer(axum::middleware::from_fn_with_state(
            state.clone(),
            middleware::jwt_auth_middleware
        ));

    let app = public_routes
        .merge(protected_routes)
        .with_state(state)
        .layer(
            ServiceBuilder::new()
                // Add security headers first (applies to all responses)
                .layer(axum::middleware::from_fn(
                    middleware::security_headers_middleware
                ))
                // Add general rate limiting
                .layer(axum::middleware::from_fn(
                    middleware::general_rate_limit_middleware
                ))
                .layer(TraceLayer::new_for_http())
                .layer(CorsLayer::permissive()),
        );

    let addr = format!("{}:{}", config.server.host, config.server.port);
    eprintln!("Binding to {}...", addr);
    let listener = tokio::net::TcpListener::bind(&addr).await?;
    eprintln!("Server listening on {}", &addr);
    tracing::info!("Server listening on {}", &addr);

    axum::serve(listener, app).await?;

    Ok(())
}
