#[cfg(all(feature = "rt", feature = "rocket"))]
#[macro_use]
extern crate rocket;

#[cfg(all(feature = "rt", feature = "rocket"))]
mod gate {
  use tokio::{sync::mpsc, task};

  use qsu::rocket::Rocket;

  use qsu::{
    async_trait,
    rt::{
      InitCtx, RocketServiceHandler, RunCtx, RunEnv, SrvAppRt, SvcEvt, TermCtx
    },
    tracing
  };

  #[derive(Debug)]
  enum MyError {}

  struct MyService {
    rx: Option<mpsc::UnboundedReceiver<SvcEvt>>
  }

  #[async_trait]
  impl RocketServiceHandler for MyService {
    type AppErr = MyError;

    async fn init(
      &mut self,
      ictx: &mut InitCtx
    ) -> Result<Vec<Rocket<rocket::Build>>, Self::AppErr> {
      tracing::info!("Running RocketServiceHandler::init()");

      ictx.report(Some("Building a rocket"));
      let rockets = vec![rocket::build().mount("/", routes![index])];

      ictx.report(Some("Finalized service handler initialization"));

      Ok(rockets)
    }

    async fn run(
      &mut self,
      mut rockets: Vec<Rocket<rocket::Ignite>>,
      _re: &RunEnv
    ) -> Result<(), Self::AppErr> {
      tracing::info!("Running RocketServiceHandler::run()");

      // Spawn a task to handle service events
      let mut rx = self.rx.take().unwrap();
      task::spawn(async move {
        loop {
          if let Some(msg) = rx.recv().await {
            tracing::info!("Application received qsu event {:?}", msg);
            if let SvcEvt::Shutdown(_) = msg {
              break;
            }
          }
        }
      });

      if let Some(rocket) = rockets.pop() {
        rocket.launch().await.unwrap();
      }

      Ok(())
    }

    async fn shutdown(
      &mut self,
      tctx: &mut TermCtx
    ) -> Result<(), Self::AppErr> {
      tracing::info!("Running RocketServiceHandler::shutdown()");
      tctx.report(Some("Terminating service handler"));

      // .. do termination here ..

      tctx.report(Some("Finalized service handler termination"));

      Ok(())
    }
  }


  pub fn main() {
    let svcname = qsu::default_service_name().unwrap();

    // Channel used to signal termination from service event handler to main
    // application
    let (tx, rx) = mpsc::unbounded_channel();

    // Service event handler
    let svcevt_handler = move |msg| {
      let _ = tx.send(msg);
    };

    // Set up main service runtime handler
    let svcrt = MyService { rx: Some(rx) };

    // Define service application runtime components
    let apprt = SrvAppRt::Rocket {
      svcevt_handler: Box::new(svcevt_handler),
      rt_handler: Box::new(svcrt)
    };

    // Launch service
    let rctx = RunCtx::new(&svcname);
    rctx.run(apprt).unwrap();
  }


  #[get("/")]
  fn index() -> &'static str {
    log::error!("error");
    log::warn!("warn");
    log::info!("info");
    log::debug!("debug");
    log::trace!("trace");

    tracing::error!("error");
    tracing::warn!("warn");
    tracing::info!("info");
    tracing::debug!("debug");
    tracing::trace!("trace");

    "Hello, world!"
  }
}


fn main() {
  #[cfg(all(feature = "rt", feature = "rocket"))]
  gate::main();

  #[cfg(not(all(feature = "rt", feature = "rocket")))]
  println!("simplerocket example requires the rt and rocket features");
}

// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :
