use anyhow::{Context, Result};
use axum::{
    middleware,
    routing::{delete, get, post, put},
    Router,
};
use std::{env, sync::Arc};
use tower::ServiceBuilder;
use tower_http::{
    cors::{Any, CorsLayer},
    trace::TraceLayer,
};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};

mod auth;
mod db;
mod email;
mod upload;
mod recurring;
mod error;
mod handlers;
mod models;

use email::{EmailConfig, Mailer};

#[derive(Clone)]
pub struct AppState {
    pub pool: sqlx::PgPool,
    pub jwt_secret: String,
    pub mailer: Arc<Mailer>,
}

#[tokio::main]
async fn main() -> Result<()> {
    // Initialize tracing
    tracing_subscriber::registry()
        .with(
            tracing_subscriber::EnvFilter::try_from_default_env()
                .unwrap_or_else(|_| "church_api=debug,tower_http=debug".into()),
        )
        .with(tracing_subscriber::fmt::layer())
        .init();

    // Load environment variables
    dotenvy::dotenv().ok();

    let database_url = env::var("DATABASE_URL").context("DATABASE_URL must be set")?;
    let jwt_secret = env::var("JWT_SECRET").context("JWT_SECRET must be set")?;

    // Initialize database
    // Database connection
    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .context("Failed to connect to database")?;

    // Run migrations (disabled temporarily)
    // sqlx::migrate!("./migrations")
    //     .run(&pool)
    //     .await
    //     .context("Failed to run migrations")?;
    let email_config = EmailConfig::from_env().map_err(|e| anyhow::anyhow!("Failed to load email config: {:?}", e))?;
    let mailer = Arc::new(Mailer::new(email_config).map_err(|e| anyhow::anyhow!("Failed to initialize mailer: {:?}", e))?);

    let state = AppState {
        pool: pool.clone(),
        jwt_secret,
        mailer,
    };

    // Create protected admin routes
    let admin_routes = Router::new()
        .route("/users", get(handlers::auth::list_users))
        .route("/bulletins", post(handlers::bulletins::create))
        .route("/bulletins/:id", put(handlers::bulletins::update))
        .route("/bulletins/:id", delete(handlers::bulletins::delete))
        .route("/events", post(handlers::events::create))
        .route("/events/:id", put(handlers::events::update))
        .route("/events/:id", delete(handlers::events::delete))
        .route("/events/pending", get(handlers::events::list_pending))
        .route("/events/pending/:id/approve", post(handlers::events::approve))
        .route("/events/pending/:id/reject", post(handlers::events::reject))
        .route("/config", get(handlers::config::get_admin_config))
        .route("/events/pending/:id", delete(handlers::events::delete_pending))
        .layer(middleware::from_fn_with_state(state.clone(), auth::auth_middleware));

    // Build our application with routes
    let app = Router::new()
        // Public routes (no auth required)
        .route("/api/auth/login", post(handlers::auth::login))
        .route("/api/bulletins", get(handlers::bulletins::list))
        .route("/api/bulletins/current", get(handlers::bulletins::current))
        .route("/api/bulletins/:id", get(handlers::bulletins::get))
        .route("/api/events", get(handlers::events::list))
        .route("/api/events/upcoming", get(handlers::events::upcoming))
        .route("/api/events/featured", get(handlers::events::featured))
        .route("/api/events/:id", get(handlers::events::get))
        .route("/api/config", get(handlers::config::get_public_config))
        // Mount protected admin routes
        .nest("/api/admin", admin_routes)
        .nest("/api/upload", upload::routes())
        .with_state(state)
        .layer(
            ServiceBuilder::new()
                .layer(TraceLayer::new_for_http())
                .layer(
                    CorsLayer::new()
                        .allow_origin(Any)
                        .allow_methods(Any)
                        .allow_headers(Any),
                ),
        );

    // Start recurring events scheduler
    recurring::start_recurring_events_scheduler(pool.clone()).await;
    let listener = tokio::net::TcpListener::bind("0.0.0.0:3002").await?;
    tracing::info!("🚀 Church API server running on {}", listener.local_addr()?);
    
    axum::serve(listener, app).await?;

    Ok(())
}

#[cfg(test)]
mod tests {
    use bcrypt::{hash, verify, DEFAULT_COST};
    
    #[test]
    fn test_bcrypt() {
        let password = "test123";
        let hashed = hash(password, DEFAULT_COST).unwrap();
        println!("Hash: {}", hashed);
        assert!(verify(password, &hashed).unwrap());
    }
}

#[cfg(test)]
mod tests4 {
    use bcrypt::{hash, DEFAULT_COST};
    
    #[test]
    fn generate_real_password_hash() {
        let password = "Alright8-Reapply-Shrewdly-Platter-Important-Keenness-Banking-Streak-Tactile";
        let hashed = hash(password, DEFAULT_COST).unwrap();
        println!("Hash for real password: {}", hashed);
    }
}
mod utils;
