//use std::collections::HashMap;
use std::fmt;
//use std::str::from_utf8;
//use tera::Tera;

use warp::{
  http::{method::Method, HeaderMap, HeaderValue},
//  Filter,
};

use reqtasks::ReqTasks;
use app_env::{
  appenv::AppEnv,
  config::Config,
  module::Module,
  AppStore,
    // AppData,
};
use app_auth::{
  AuthStore,
  UserCtx,
  LoginRequest,
  // BEARER_PREFIX,
  // AuthError,
};

/// `ReqEnv` includes ReqTasks as core type
/// it is a kind of wrapping type 
/// to declare:
/// - auth methods locally 
/// - other attributes
/// - other request tasks methods 
/// 
#[derive(Clone)]
pub struct ReqEnv {
 pub req: ReqTasks,

}

impl fmt::Display for ReqEnv {
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
   write!(f, "{} {} {}", &self.req.path, &self.req.origin, &self.req.key_module)
  }
}

impl ReqEnv {
  pub fn new(
    app_db: AppStore,
    auth_store: AuthStore,
    header: HeaderMap<HeaderValue>,
    method: Method,
    path: &str,
    origin: &str,
    key_module: &str
  ) -> Self {
    let app_data = app_db.app_data.read();
    // let auth_store: &'a AuthStore = &AuthStore {
    //   users: auth_db.users.clone(),
    //   sessions: auth_db.sessions.clone(),
    //   enforcer: auth_db.enforcer.clone(),
    // };
    Self {
      req: ReqTasks {
        app_data: app_data.to_owned(),
        auth_store: auth_store.to_owned(),
        header,
        method,
        path: format!("{}{}",key_module,path).to_string(),
        origin: format!("{}{}",key_module,origin).to_string(),
        key_module: key_module.to_string(),
      },
    }
  }
  /// Get `AppEnv`
  #[must_use]
  pub fn env(&self) -> AppEnv {
    self.req.env()
  }
  /// Get Tera
  #[must_use]
  pub fn tera(&self) -> tera::Tera {
    self.req.tera()
  }
  /// Get Context (ctx)
  #[must_use]
  pub fn ctx(&self) -> tera::Context {
    self.req.ctx()
  }
  /// Get `AppEnv` Config
  #[must_use]
  pub fn config(&self) -> Config {
    self.req.config()
  }
  #[must_use]
  pub fn module(&self) -> Module {
    self.req.module()
  }
  #[must_use]
  pub fn lang(&self) -> String {
    self.req.lang()
  }
  #[allow(clippy::missing_errors_doc)]
  pub fn token_from_header(&self) -> anyhow::Result<String> {
    self.req.token_from_header()
  }
  #[allow(clippy::missing_errors_doc)]
  pub async fn token_session(&self, login: &LoginRequest) -> anyhow::Result<String> {
    self.req.token_session(login).await
  }
  #[allow(clippy::missing_errors_doc)]
  pub async fn user_authentication(&self) -> anyhow::Result<UserCtx> {
    self.req.user_authentication().await
  }
}