use actix_web::{cookie, HttpRequest, HttpResponseBuilder};
use handlebars::Handlebars;
use tokio::sync::Mutex;
use ttl_cache::TtlCache;
use uuid::Uuid;

pub mod atom;
pub mod cookies_policy;
pub mod index;
pub mod log_in;
pub mod log_out;
pub mod my;
pub mod query_reset_game_pwd;
pub mod reset_game_pwd;
pub mod slow_game;
pub mod slow_games;
pub mod well_known;

pub mod templates {
    pub const INDEX: &str = "index";
    pub const MY: &str = "my";
    pub const RESET_GAME_PWD: &str = "reset-game-pwd";
    pub const QUERY_RESET_GAME_PWD: &str = "query-reset-game-pwd";
    pub const SLOW_GAMES: &str = "slow-games";
    pub const SLOW_GAME: &str = "slow-game";
    pub const COOKIES_POLICY: &str = "cookies-policy";
    pub const LOG_IN: &str = "log-in";

    pub const ATOM_TURNS: &str = "atom-turns";
    pub const ATOM_GAMES: &str = "atom-games";

    pub mod sub {
        pub const FOOTER: &str = "footer";
        pub const HEADER: &str = "header";
    }
}

#[derive(serde_derive::Serialize)]
pub struct CommonAuthInfo<'a> {
    pub user: Option<std::borrow::Cow<'a, str>>,
}

pub struct WebData<'a> {
    pub handlebars: Handlebars<'a>,
    pub handlebars_xml: Handlebars<'a>,
    pub cache_reset_game_pwd: Mutex<TtlCache<Uuid, (Uuid, String, bool)>>,
    pub cache_query_reset_game_pwd: Mutex<TtlCache<Uuid, ()>>,
    pub cache_login: Mutex<TtlCache<Uuid, ()>>,
    pub cache_join_game: Mutex<TtlCache<Uuid, (String, String)>>,
    /// Cache for game (gameuid, player_name)
    pub cache_leave_game: Mutex<TtlCache<Uuid, (String, String)>>,
    pub cache_query_delegation_game: Mutex<TtlCache<Uuid, (String, String)>>,
    /// Cache for delegation data (gameuid, player_name, delegate_name)
    pub cache_revoke_delegation_game: Mutex<TtlCache<Uuid, (String, String, String)>>,
    pub cache_delegation_game: Mutex<TtlCache<Uuid, (String, String, String)>>,
    pub cache_duration_sec: u64,
    pub base_proto: String,
    pub base_domain: String,
    pub mailer: lettre::AsyncSmtpTransport<lettre::Tokio1Executor>,
    pub mailer_from: lettre::message::Mailbox,
    pub xmpp_url: String,
    pub cookies_key: actix_web::cookie::Key,
    pub set_cookie_domain: bool,
    pub freeorion_version: String,
}

pub struct DataBaseRo(pub deadpool_postgres::Pool);
pub struct DataBaseRw(pub deadpool_postgres::Pool);

pub fn insert_security_headers(mut response: HttpResponseBuilder) -> HttpResponseBuilder {
    response
        .insert_header((actix_web::http::header::X_FRAME_OPTIONS, "DENY"))
        .insert_header((
            actix_web::http::header::CONTENT_SECURITY_POLICY,
            "default-src 'none'; frame-ancestors 'none'; object-src 'none'; script-src 'none'; style-src 'self'; img-src 'self'",
        ))
        .insert_header((actix_web::http::header::REFERRER_POLICY, "same-origin"))
        .insert_header((actix_web::http::header::X_XSS_PROTECTION, "1; mode=block"));
    response
}

pub fn request_to_jar(request: HttpRequest) -> cookie::CookieJar {
    let mut jar = cookie::CookieJar::new();
    match request.cookies() {
        Ok(cookies) => {
            for cookie in &*cookies {
                jar.add_original(cookie.clone());
            }
        }
        Err(e) => {
            log::error!("Cann't get cookies from request: {}", e);
        }
    }
    jar
}

pub fn naive_to_text(ts: &chrono::NaiveDateTime) -> String {
    use chrono::TimeZone;
    chrono::Utc::from_utc_datetime(&chrono::Utc, ts)
        .format("%Y %b %d %H:%M UTC")
        .to_string()
}