//!
//!
#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_migrations;

use diesel::{
  r2d2::{ConnectionManager, Pool},
  PgConnection,
};
use std::env;

mod api;
mod compositions;
mod core;
mod events;
mod repositories;
mod schedulers;
mod services;

diesel_migrations::embed_migrations!();

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
  let url_db = match env::var_os("URL_DATABASE") {
    Some(v) => v.into_string().unwrap(),
    None => "".to_string(),
  };

  let url_server_broker = match env::var_os("URL_BROKER") {
    Some(v) => v.into_string().unwrap(),
    None => "".to_string(),
  };
  let queue_server_broker = match env::var_os("QUEUE_BROKER") {
    Some(v) => v.into_string().unwrap(),
    None => "".to_string(),
  };

  let k_url = match env::var_os("K_URL") {
    Some(v) => v.into_string().unwrap(),
    None => "".to_string(),
  };
  let k_username = match env::var_os("K_USERNAME") {
    Some(v) => v.into_string().unwrap(),
    None => "".to_string(),
  };
  let k_secret = match env::var_os("K_SECRET") {
    Some(v) => v.into_string().unwrap(),
    None => "".to_string(),
  };

  let api_config = core::config::ApiConfig {
    k_url,
    k_username,
    k_secret,
  };

  let manager = ConnectionManager::<PgConnection>::new(url_db);
  let pool = Pool::builder()
    .max_size(4)
    .test_on_check_out(true)
    .build(manager)?;
  let conn = pool.get()?;

  embedded_migrations::run(&conn)?;

  let server_broker_opts = nats::asynk::Options::new();
  let connection_server_broker = server_broker_opts.connect(url_server_broker).await?;

  let mut sched = tokio_cron_scheduler::JobScheduler::new().await?;

  let member_scheduler = schedulers::member::scheduler::Scheduler::get_instance(
    pool.clone(),
    sched.clone(),
    api_config.clone(),
  )?;
  member_scheduler.queue().await?;
  let balance_scheduler = schedulers::balance::scheduler::Scheduler::get_instance(
    pool.clone(),
    sched.clone(),
    api_config.clone(),
  )?;
  balance_scheduler.queue().await?;
  let game_scheduler = schedulers::game::scheduler::Scheduler::get_instance(
    pool.clone(),
    sched.clone(),
    api_config.clone(),
  )?;
  game_scheduler.queue().await?;

  let _h_scheduler = sched.start().await?;

  let vendor_service = services::vendor::service::Service::new(
    connection_server_broker.clone(),
    queue_server_broker.clone(),
    pool.clone(),
  );
  let game_service = services::game::service::Service::new(
    connection_server_broker.clone(),
    queue_server_broker.clone(),
    pool.clone(),
  );
  let member_service = services::member::service::Service::new(
    connection_server_broker.clone(),
    queue_server_broker.clone(),
  );
  let member_account_service = services::member_account::service::Service::new(
    connection_server_broker.clone(),
    queue_server_broker.clone(),
  );
  let betting_service = services::betting::service::Service::new(
    connection_server_broker.clone(),
    queue_server_broker.clone(),
  );

  let member_event_handler = events::member::event::EventHandler::new(
    connection_server_broker.clone(),
    queue_server_broker.clone(),
    pool.clone(),
    api_config.clone(),
  );

  println!("Server service [beteran-api-kgon-server-service] is started");

  futures::try_join!(
    vendor_service.subscribe(),
    game_service.subscribe(),
    // member_service.subscribe(),
    // member_account_service.subscribe(),
    // betting_service.subscribe(),
    member_event_handler.subscribe(),
  )?;

  sched.shutdown().await?;

  Ok(())
}