mod auth_guard;
mod k8s;
mod routes;
mod state;
mod stripe;

use std::sync::Arc;

use axum::{Router, routing::{get, post}};
use tower_http::services::ServeDir;
use openid::DiscoveredClient;
use state::AppState;
use tower_sessions::{MemoryStore, SessionManagerLayer};
use irc_now_common::auth::OidcConfig;
use irc_now_common::db::DbConfig;

async fn health() -> &'static str {
    "ok"
}

#[tokio::main]
async fn main() {
    tracing_subscriber::fmt()
        .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
        .init();

    let db = DbConfig::from_env("ACCOUNTS").connect().await.unwrap();
    let oidc = OidcConfig::from_env();

    let issuer_url = url::Url::parse(&oidc.issuer_url).expect("invalid OIDC issuer URL");

    tracing::info!("discovering OIDC provider at {issuer_url}");
    let oidc_client = DiscoveredClient::discover(
        oidc.client_id.clone(),
        oidc.client_secret.clone(),
        Some(oidc.redirect_url.clone()),
        issuer_url,
    )
    .await
    .expect("OIDC discovery failed");

    tracing::info!("OIDC provider discovered");

    let stripe_webhook_secret =
        std::env::var("STRIPE_WEBHOOK_SECRET").unwrap_or_default();

    let state = AppState {
        db,
        oidc,
        oidc_client: Arc::new(oidc_client),
        stripe_webhook_secret,
    };

    let session_store = MemoryStore::default();
    let session_layer = SessionManagerLayer::new(session_store);

    let app = Router::new()
        .route("/health", get(health))
        .route("/auth/login", get(routes::auth::login))
        .route("/auth/callback", get(routes::auth::callback))
        .route("/auth/logout", get(routes::auth::logout))
        .route("/dashboard", get(routes::dashboard::index))
        .route("/bouncers", get(routes::bouncer::list))
        .route("/bouncers/create", post(routes::bouncer::create))
        .route("/billing", get(routes::billing::portal))
        .route("/billing/webhook", post(routes::billing::webhook))
        .nest_service("/static", ServeDir::new("static"))
        .layer(session_layer)
        .with_state(state);

    let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await.unwrap();
    tracing::info!("listening on {}", listener.local_addr().unwrap());
    axum::serve(listener, app).await.unwrap();
}
