use crate::common::config::AppConfig;
use crate::common::di::AppState;
use axum::http::header::{CACHE_CONTROL, HeaderValue};
use axum::{Router, response::Html, routing::get};
use std::sync::Arc;
use tower_http::compression::CompressionLayer;
use tower_http::services::ServeDir;
use tower_http::set_header::SetResponseHeaderLayer;

/// Creates web routes for serving static files
pub fn create_web_routes() -> Router<Arc<AppState>> {
    // Get config to access static path
    let config = AppConfig::from_env();

    // XXX do we prefer PROFILE or ENV ?
    let is_dev = std::env::var("PROFILE").is_ok_and(|profile| profile == "dev");

    let assets_dir = if is_dev {
        // take directly the source (permits faster development)
        "static"
    } else {
        // take the compiled assets
        "static-dist"
    };

    // In release builds, serve from static-dist/ (processed assets).
    // In debug builds, serve from the original static/ directory.
    let static_path = if cfg!(not(debug_assertions)) {
        let dist = config
            .static_path
            .parent()
            .unwrap_or(std::path::Path::new("."))
            .join(assets_dir);
        if dist.exists() {
            dist
        } else {
            config.static_path.clone()
        }
    } else {
        config.static_path.clone()
    };

    // Static assets (JS, CSS, JSON, SVG, ICO) served via ServeDir
    // with brotli + gzip compression and aggressive caching (7 days).
    // HTML pages are served via explicit routes (include_str!) and
    // do NOT pass through these layers.
    let static_service = ServeDir::new(&static_path);

    // By default assets are cached in release/production environement and no cache in dev
    let cache_control_value = if is_dev {
        "max-age=0, no-cache, no-store"
    } else {
        "public, max-age=604800, stale-while-revalidate=86400"
    };

    Router::new()
        // Add specific routes for clean URLs (without .html)
        .route("/login", get(serve_login_page))
        .route("/profile", get(serve_profile_page))
        .route("/admin", get(serve_admin_page))
        .route("/device", get(serve_device_verify_page))
        .route("/s/{token}", get(serve_share_page))
        // Serve static files with compression + cache headers
        .fallback_service(static_service)
        .layer(CompressionLayer::new().br(true).gzip(true))
        .layer(SetResponseHeaderLayer::if_not_present(
            CACHE_CONTROL,
            HeaderValue::from_static(cache_control_value),
        ))
}

/// Serve the login page
async fn serve_login_page() -> Html<&'static str> {
    Html(include_str!(concat!(env!("OUT_DIR"), "/login.html")))
}

/// Serve the profile page
async fn serve_profile_page() -> Html<&'static str> {
    Html(include_str!(concat!(env!("OUT_DIR"), "/profile.html")))
}

/// Serve the admin page
async fn serve_admin_page() -> Html<&'static str> {
    Html(include_str!(concat!(env!("OUT_DIR"), "/admin.html")))
}

/// Serve the device verification page (RFC 8628 Device Authorization Grant)
async fn serve_device_verify_page() -> Html<&'static str> {
    Html(include_str!(concat!(
        env!("OUT_DIR"),
        "/device-verify.html"
    )))
}

/// Serve the public share page (unauthenticated)
async fn serve_share_page() -> Html<&'static str> {
    Html(include_str!(concat!(env!("OUT_DIR"), "/share.html")))
}
