use anyhow::{Context, Result};
use axum::{
    extract::Path,
    middleware,
    response::Redirect,
    routing::{delete, get, post, put},
    Router,
    response::Html,
};
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 utils;
mod handlers;
mod models;
mod services;
mod app_state;

use email::{EmailConfig, Mailer};
use app_state::AppState;

#[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))?);

    // Initialize Owncast service with default values
    let owncast_host = env::var("OWNCAST_HOST").unwrap_or_else(|_| "stream.rockvilletollandsda.church".to_string());
    let stream_host = env::var("STREAM_HOST").unwrap_or_else(|_| "stream.rockvilletollandsda.church".to_string());
    let owncast_service = Some(Arc::new(services::OwncastService::new(&owncast_host, &stream_host)));

    // Transcoding services removed - replaced by simple smart streaming system
    tracing::info!("🎬 Using direct AV1/H.264 smart streaming - no complex transcoding needed");

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

    // 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/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("/events/pending/:id", delete(handlers::events::delete_pending))
        .route("/events/:id", put(handlers::events::update))
        .route("/events/:id", delete(handlers::events::delete))
        .route("/config", get(handlers::config::get_admin_config))
        .route("/schedule", post(handlers::schedule::create_schedule))
        .route("/schedule/:date", put(handlers::schedule::update_schedule))
        .route("/schedule/:date", delete(handlers::schedule::delete_schedule))
        .route("/schedule", get(handlers::schedule::list_schedules))
        .route("/members", get(handlers::members::list))
        .route("/members", post(handlers::members::create))
        .route("/members/:id", delete(handlers::members::delete))
        .route("/backup/create", post(handlers::backup::create_backup))
        .route("/backup/list", get(handlers::backup::list_backups))
        .route("/backup/cleanup", post(handlers::backup::cleanup_backups))
        .route("/backup/now", post(handlers::backup::backup_now))
        .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/next", get(handlers::bulletins::next))
    .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/submit", post(handlers::events::submit))
    .route("/api/events/:id", get(handlers::events::get))
    .route("/api/config", get(handlers::config::get_public_config))
    .route("/api/config/recurring-types", get(handlers::config::get_recurring_types))
    .route("/api/collections/rtsda_android/records", get(handlers::legacy::android_update))
    .route("/api/bible_verses/random", get(handlers::bible_verses::random))
    .route("/api/bible_verses", get(handlers::bible_verses::list))
    .route("/api/bible_verses/search", get(handlers::bible_verses::search))
    .route("/api/contact", post(handlers::contact::submit_contact))
    .route("/api/schedule", get(handlers::schedule::get_schedule))
    .route("/api/conference-data", get(handlers::schedule::get_conference_data))
    .route("/api/members/active", get(handlers::members::list_active))
    // New media library endpoints (replacing Jellyfin)
    .route("/api/sermons", get(handlers::media::list_sermons))
    .route("/api/livestreams", get(handlers::media::list_livestreams))
    .route("/api/media/items", get(handlers::media::list_media_items))
    .route("/api/media/items/:id", get(handlers::media::get_media_item))
    // 🎯 SMART STREAMING - AV1 direct, HLS for legacy (like Jellyfin but not shit)
    .route("/api/media/stream/:media_id", get(handlers::smart_streaming::smart_video_streaming))
    .route("/api/media/stream/:media_id/playlist.m3u8", get(handlers::smart_streaming::generate_hls_playlist_for_segment_generation))
    .route("/api/media/stream/:media_id/:segment_name", get(handlers::smart_streaming::serve_hls_segment))
    .route("/api/media/:media_id/thumbnail", get(handlers::smart_streaming::serve_thumbnail))
    // Legacy chunk streaming API removed - never released transcoding nightmare
    // Test pages
    .route("/chunk-test", get(serve_chunk_test_page))
    .route("/smart-test", get(serve_smart_test_page))
    .route("/api/media/thumbnail/:id", get(handlers::media::get_thumbnail))
    // Legacy Jellyfin endpoints (keep for compatibility during transition)
    // Jellyfin debug routes removed - clients hit Jellyfin directly now
    .route("/api/stream/status", get(handlers::owncast::get_stream_status))
    .route("/api/stream/live", get(handlers::owncast::get_live_status))
    .route("/api/stream/hls/stream.m3u8", get(handlers::owncast::proxy_hls_playlist))
    .route("/api/stream/hls/:variant/stream.m3u8", get(handlers::owncast::proxy_hls_variant))
    .route("/api/stream/hls/:variant/:segment", get(handlers::owncast::proxy_hls_segment))
    .route("/api/v1/stream/status", get(handlers::owncast::get_stream_status))
    // V2 API routes with enhanced timezone handling
    .route("/api/v2/events", get(handlers::v2::events::list))
    .route("/api/v2/events/upcoming", get(handlers::v2::events::get_upcoming))
    .route("/api/v2/events/featured", get(handlers::v2::events::get_featured))
    .route("/api/v2/events/submit", post(handlers::v2::events::submit))
    .route("/api/v2/events/:id", get(handlers::v2::events::get_by_id))
    .route("/api/v2/bulletins", get(handlers::v2::bulletins::list))
    .route("/api/v2/bulletins/current", get(handlers::v2::bulletins::get_current))
    .route("/api/v2/bulletins/next", get(handlers::v2::bulletins::get_next))
    .route("/api/v2/bulletins/:id", get(handlers::v2::bulletins::get_by_id))
    .route("/api/v2/bible_verses/random", get(handlers::v2::bible_verses::get_random))
    .route("/api/v2/bible_verses", get(handlers::v2::bible_verses::list))
    .route("/api/v2/bible_verses/search", get(handlers::v2::bible_verses::search))
    .route("/api/v2/contact", post(handlers::v2::contact::submit_contact))
    .route("/api/v2/schedule", get(handlers::v2::schedule::get_schedule))
    .route("/api/v2/conference-data", get(handlers::v2::schedule::get_conference_data))
    // Redirect /api/v1/* to /api/*
    .route("/api/v1/*path", get(redirect_v1_to_api))
    // Mount protected admin routes (with chunk streaming cleanup)
    .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;
    
    // Start database backup scheduler
    let backup_database_url = database_url.clone();
    tokio::spawn(async move {
        use services::BackupScheduler;
        
        let scheduler = BackupScheduler::default_config(backup_database_url);
        if let Err(e) = scheduler.start().await {
            tracing::error!("Backup scheduler failed: {}", e);
        }
    });
    
    // Start periodic media scanning (disabled initial scan for performance)
    let media_pool = pool.clone();
    tokio::spawn(async move {
        use services::MediaScanner;
        let scanner = MediaScanner::new(media_pool);
        
        // Wait 30 seconds after startup before first scan to allow server to settle
        tokio::time::sleep(tokio::time::Duration::from_secs(30)).await;
        
        // Periodic scanning every 10 minutes (reduced frequency for performance)
        let mut interval = tokio::time::interval(tokio::time::Duration::from_secs(600));
        loop {
            interval.tick().await;
            tracing::info!("Starting periodic media scan...");
            
            if let Err(e) = scanner.scan_directory("/media/archive/jellyfin/sermons").await {
                tracing::error!("Periodic sermons scan failed: {:?}", e);
            }
            if let Err(e) = scanner.scan_directory("/media/archive/jellyfin/livestreams").await {
                tracing::error!("Periodic livestreams scan failed: {:?}", e);
            }
            
            tracing::info!("Periodic media scan completed");
        }
    });
    
    // Start Intel Arc A770 background thumbnail generation
    tokio::spawn(async move {
        use services::ThumbnailGenerator;
        
        // Wait 60 seconds after startup to allow server to settle and media scan to complete
        tokio::time::sleep(tokio::time::Duration::from_secs(60)).await;
        
        tracing::info!("🚀 Starting Intel Arc A770 background thumbnail generation");
        
        // Run thumbnail generation every 30 minutes
        let mut interval = tokio::time::interval(tokio::time::Duration::from_secs(1800));
        loop {
            interval.tick().await;
            tracing::info!("📸 Starting Arc A770 thumbnail generation scan...");
            
            // Generate thumbnails for sermons directory
            if let Err(e) = ThumbnailGenerator::scan_and_generate_missing_thumbnails(
                "/media/archive/jellyfin/sermons",
                &format!("{}/thumbnails", 
                    std::env::var("UPLOAD_DIR").unwrap_or_else(|_| "/opt/rtsda/church-api/uploads".to_string()))
            ).await {
                tracing::error!("Sermons thumbnail generation failed: {:?}", e);
            }
            
            // Generate thumbnails for livestreams directory  
            if let Err(e) = ThumbnailGenerator::scan_and_generate_missing_thumbnails(
                "/media/archive/jellyfin/livestreams",
                &format!("{}/thumbnails", 
                    std::env::var("UPLOAD_DIR").unwrap_or_else(|_| "/opt/rtsda/church-api/uploads".to_string()))
            ).await {
                tracing::error!("Livestreams thumbnail generation failed: {:?}", e);
            }
            
            tracing::info!("📸 Arc A770 thumbnail generation scan completed");
        }
    });
    
    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(())
}

/// Serve the chunk streaming test page
async fn serve_chunk_test_page() -> Html<String> {
    let html = include_str!("../chunk_streaming_test.html");
    Html(html.to_string())
}

/// Serve the smart streaming test page
async fn serve_smart_test_page() -> Html<String> {
    let html = include_str!("../smart_streaming_test.html");
    Html(html.to_string())
}

/// Redirect /api/v1/* requests to /api/*
async fn redirect_v1_to_api(Path(path): Path<String>) -> Redirect {
    let new_path = format!("/api/{}", path);
    Redirect::permanent(&new_path)
}

#[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);
    }
}
