use sqlpage::{
    AppState,
    app_config::AppConfig,
    cli, telemetry,
    webserver::{self, Database},
};

#[actix_web::main]
async fn main() {
    let cli = match cli::arguments::parse_cli() {
        Ok(cli) => cli,
        Err(e) => {
            eprintln!("{e:#}");
            std::process::exit(1);
        }
    };

    let is_server_mode = cli.command.is_none();

    if is_server_mode {
        if let Err(e) = init_logging() {
            eprintln!("Failed to initialize logging/telemetry: {e:#}");
            std::process::exit(1);
        }
    } else {
        let _ = dotenvy::dotenv();
    }

    if let Err(e) = start(cli).await {
        if is_server_mode {
            log::error!("{e:?}");
        } else {
            eprintln!("{e:#}");
        }
        std::process::exit(1);
    }
}

async fn start(cli: cli::arguments::Cli) -> anyhow::Result<()> {
    let app_config = AppConfig::from_cli(&cli)?;

    if let Some(command) = cli.command {
        return command.execute(app_config).await;
    }

    let db = Database::init(&app_config).await?;
    webserver::database::migrations::apply(&app_config, &db).await?;
    let state = AppState::init_with_db(&app_config, db).await?;

    log::debug!("Starting server...");
    webserver::http::run_server(&app_config, state).await?;
    log::info!("Server stopped gracefully. Goodbye!");
    telemetry::shutdown_telemetry();
    Ok(())
}

fn init_logging() -> anyhow::Result<()> {
    let load_env = dotenvy::dotenv();

    let otel_active = telemetry::init_telemetry()?;

    match load_env {
        Ok(path) => log::info!("Loaded environment variables from {path:?}"),
        Err(dotenvy::Error::Io(e)) if e.kind() == std::io::ErrorKind::NotFound => log::debug!(
            "No .env file found, using only environment variables and configuration files"
        ),
        Err(e) => log::error!("Error loading .env file: {e}"),
    }

    if otel_active {
        log::info!("OpenTelemetry tracing enabled (OTEL_EXPORTER_OTLP_ENDPOINT is set)");
    }

    Ok(())
}
