#![recursion_limit = "256"]
//! Owner app server entry point.
//!
//! This server runs on port 3001 and serves the admin UI with the
//! `chattyness_owner` database role (no RLS restrictions).

#[cfg(feature = "ssr")]
mod server {
    use axum::{response::Redirect, routing::get, Router};
    use clap::Parser;
    use leptos::prelude::*;
    use leptos_axum::{generate_route_list, LeptosRoutes};
    use sqlx::postgres::PgPoolOptions;
    use std::net::SocketAddr;
    use std::path::Path;
    use tower_http::services::ServeDir;
    use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};

    use chattyness_admin_ui::{admin_shell, AdminApp, AdminAppState};

    /// CLI arguments.
    #[derive(Parser)]
    #[command(name = "chattyness-owner")]
    #[command(about = "Chattyness Owner Admin Server")]
    struct Args {
        /// Host to bind to
        #[arg(long, env = "HOST", default_value = "127.0.0.1")]
        host: String,

        /// Port to bind to
        #[arg(long, env = "OWNER_PORT", default_value = "3001")]
        port: u16,

        /// Database password for chattyness_owner role
        #[arg(long, env = "DB_CHATTYNESS_OWNER")]
        db_password: String,

        /// Use secure cookies
        #[arg(long, env = "SECURE_COOKIES", default_value = "false")]
        secure_cookies: bool,
    }

    pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
        // Load environment variables
        dotenvy::dotenv().ok();

        // Initialize logging
        tracing_subscriber::registry()
            .with(
                tracing_subscriber::EnvFilter::try_from_default_env()
                    .unwrap_or_else(|_| "chattyness_owner=debug,tower_http=debug".into()),
            )
            .with(tracing_subscriber::fmt::layer())
            .init();

        // Parse arguments
        let args = Args::parse();

        tracing::info!("Starting Chattyness Owner Server");

        // Create database pool for owner access (fixed connection string)
        let database_url = format!(
            "postgres://chattyness_owner:{}@localhost/chattyness",
            args.db_password
        );
        let pool = PgPoolOptions::new()
            .max_connections(10)
            .connect(&database_url)
            .await?;

        tracing::info!("Connected to database (owner role)");

        // Configure Leptos
        let cargo_toml = concat!(env!("CARGO_MANIFEST_DIR"), "/Cargo.toml");
        let conf = get_configuration(Some(cargo_toml)).unwrap();
        let leptos_options = conf.leptos_options;
        let addr = SocketAddr::new(args.host.parse()?, args.port);

        // Create session layer
        let session_layer =
            chattyness_admin_ui::auth::create_admin_session_layer(pool.clone(), args.secure_cookies)
                .await;

        // Create app state
        let app_state = AdminAppState {
            pool: pool.clone(),
            leptos_options: leptos_options.clone(),
        };

        // Generate routes
        let routes = generate_route_list(AdminApp);

        // Get site paths from Leptos config
        // site_root is relative to workspace root, make it absolute
        let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
        let workspace_root = manifest_dir.parent().unwrap().parent().unwrap();
        let site_root = workspace_root.join(&*leptos_options.site_root);
        let static_dir = site_root.join("static");
        let favicon_path = manifest_dir.join("public/favicon.ico");

        tracing::info!("Serving static files from: {}", site_root.display());

        // Admin CSS path
        let admin_css_path = static_dir.join("chattyness-owner.css");

        // Shared assets directory for uploaded files (realm images, etc.)
        let assets_dir = Path::new("/srv/chattyness/assets");

        // Build the app
        let app = Router::new()
            // Redirect root to admin
            .route("/", get(|| async { Redirect::permanent("/admin") }))
            // Nest API routes under /api/admin (matches frontend expectations when UI is at /admin)
            .nest("/api/admin", chattyness_admin_ui::api::admin_api_router().with_state(app_state.clone()))
            // Uploaded assets (realm backgrounds, props, etc.) - must come before /static
            .nest_service("/assets/server", ServeDir::new(assets_dir.join("server")))
            .nest_service("/static/realm", ServeDir::new(assets_dir.join("realm")))
            // Static files (build output: JS, CSS, WASM)
            .nest_service("/static", ServeDir::new(&static_dir))
            .nest_service("/favicon.ico", tower_http::services::ServeFile::new(&favicon_path))
            // Serve admin CSS at standardized path
            .nest_service("/static/css/admin.css", tower_http::services::ServeFile::new(&admin_css_path))
            // Leptos routes
            .leptos_routes(&app_state, routes, {
                let leptos_options = leptos_options.clone();
                move || admin_shell(leptos_options.clone())
            })
            // Apply session middleware
            .layer(session_layer)
            .with_state(app_state);

        tracing::info!("Listening on http://{}", addr);

        // Start server
        let listener = tokio::net::TcpListener::bind(&addr).await?;
        axum::serve(listener, app.into_make_service()).await?;

        Ok(())
    }
}

#[cfg(feature = "ssr")]
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    server::main().await
}

#[cfg(not(feature = "ssr"))]
fn main() {
    // This is for WASM build, which is handled by lib.rs
}
