//! {{project_name_pascal}} API server.

{{#if has_config}}
use tideway::{init_tracing_with_config, App};
use crate::config::AppConfig;
{{else}}
use tideway::{init_tracing, App};
{{/if}}
{{#if needs_arc}}
use std::sync::Arc;
{{/if}}
{{#if has_database_feature}}
use tideway::{AppContext, SeaOrmPool};
{{/if}}
{{#if has_auth_feature}}
use axum::Extension;
use crate::auth::{AuthModule, SimpleAuthProvider};
use tideway::auth::{JwtIssuer, JwtIssuerConfig};
{{/if}}

mod routes;
{{#if has_openapi_feature}}
mod openapi_docs;
{{/if}}
{{#if has_auth_feature}}
mod auth;
{{/if}}
{{#if has_database_feature}}
mod entities;
{{/if}}
{{#if has_config}}
mod config;
mod error;
{{/if}}

#[tokio::main]
async fn main() -> Result<(), std::io::Error> {
{{#if has_config}}
    let config = AppConfig::from_env();
    init_tracing_with_config(&config.tideway);
{{else}}
    init_tracing();
    {{#if has_openapi_feature}}
    let config = tideway::ConfigBuilder::new()
        .from_env()
        .build()
        .expect("Invalid TIDEWAY_* config");
    {{/if}}
{{/if}}

{{#if has_database_feature}}
    {{#if has_config}}
    let database_url = config
        .database_url
        .clone()
        .expect("DATABASE_URL is not set");
    {{else}}
    let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL is not set");
    {{/if}}
    let db = sea_orm::Database::connect(&database_url)
        .await
        .expect("Failed to connect to database");
{{/if}}

{{#if has_auth_feature}}
    {{#if has_config}}
    let jwt_secret = config
        .jwt_secret
        .clone()
        .expect("JWT_SECRET is not set");
    {{else}}
    let jwt_secret = std::env::var("JWT_SECRET").expect("JWT_SECRET is not set");
    {{/if}}
    let jwt_issuer = Arc::new(JwtIssuer::new(JwtIssuerConfig::with_secret(
        &jwt_secret,
        "{{project_name}}",
    )).expect("Failed to create JWT issuer"));
    let auth_provider = SimpleAuthProvider::from_secret(&jwt_secret);
    let auth_module = AuthModule::new(jwt_issuer.clone());
{{/if}}

{{#if has_config}}
    // tideway:app-builder:start
    let app = App::with_config(config.tideway.clone())
{{else}}
    // tideway:app-builder:start
    let app = App::new()
{{/if}}
{{#if has_auth_feature}}
        .with_global_layer(Extension(auth_provider))
        .register_module(auth_module)
{{/if}}
{{#if has_database_feature}}
        .with_context(
            AppContext::builder()
                .with_database(Arc::new(SeaOrmPool::new(db, database_url)))
                .build()
        )
{{/if}}
        .register_module(routes::ApiModule);
    // tideway:app-builder:end

{{#if has_openapi_feature}}
    let app = if {{#if has_config}}config.tideway{{else}}config{{/if}}.openapi.enabled {
        let openapi = tideway::openapi_merge_module!(openapi_docs, ApiDoc);
        let openapi_router = tideway::openapi::create_openapi_router(
            openapi,
            &{{#if has_config}}config.tideway{{else}}config{{/if}}.openapi,
        );
        app.merge_router(openapi_router)
    } else {
        app
    };
{{/if}}

    app.serve().await
}
