#[macro_use]
extern crate rocket;
#[macro_use]
extern crate rocket_okapi;

use clap::Parser;
use dotenvy::dotenv;
use log::info;
use nym_bin_common::logging::setup_logging;
use nym_network_defaults::setup_env;
use nym_task::TaskManager;

pub(crate) mod cache;
mod client;
pub(crate) mod commands;
mod country_statistics;
mod gateways;
mod geo_ip;
mod guards;
mod helpers;
mod http;
mod location;
mod mix_node;
pub(crate) mod mix_nodes;
mod overview;
mod ping;
pub(crate) mod service_providers;
mod state;
mod tasks;
mod validators;

const COUNTRY_DATA_REFRESH_INTERVAL: u64 = 60 * 15; // every 15 minutes

#[tokio::main]
async fn main() {
    dotenv().ok();
    setup_logging();
    let args = commands::Cli::parse();
    setup_env(args.config_env_file);
    let mut explorer_api = ExplorerApi::new();
    explorer_api.run().await;
}

pub struct ExplorerApi {
    state: state::ExplorerApiStateContext,
}

impl ExplorerApi {
    fn new() -> ExplorerApi {
        ExplorerApi {
            state: state::ExplorerApiStateContext::new(),
        }
    }

    async fn run(&mut self) {
        info!("Explorer API starting up...");

        let nym_api_url = self.state.inner.validator_client.api_endpoint();
        info!("Using validator API - {}", nym_api_url);

        let shutdown = TaskManager::default();

        // spawn concurrent tasks
        crate::tasks::ExplorerApiTasks::new(self.state.clone(), shutdown.subscribe()).start();
        country_statistics::distribution::CountryStatisticsDistributionTask::new(
            self.state.clone(),
            shutdown.subscribe(),
        )
        .start();
        country_statistics::geolocate::GeoLocateTask::new(self.state.clone(), shutdown.subscribe())
            .start();

        // Rocket handles shutdown on it's own, but its shutdown handling should be incorporated
        // with that of the rest of the tasks.
        // Currently it's runtime is forcefully terminated once the explorer-api exits.
        http::start(self.state.clone());

        // wait for user to press ctrl+C
        self.wait_for_interrupt(shutdown).await
    }

    async fn wait_for_interrupt(&self, shutdown: TaskManager) {
        let _res = shutdown.catch_interrupt().await;
        log::info!("Stopping explorer API");
    }
}
