use dotenvy::dotenv;
use std::env;

use axum::{Extension,serve};
use axum::extract::{
    State,
    ws::{Message, WebSocket, WebSocketUpgrade},
};
use axum::http::{HeaderValue, Method};

use jsonwebtoken::{DecodingKey, EncodingKey};
use reqwest::header::{
    AUTHORIZATION,
    CONTENT_TYPE,
    USER_AGENT};

use tokio::net::TcpListener;
use tower_http::cors::{Any, CorsLayer};

use dashmap::DashMap;
use r2d2::Pool;
use r2d2_sqlite::SqliteConnectionManager;
use std::sync::Arc;

use crate::routes::create_router;    
use crate::utils::auth::JwtKeys;
use crate::utils::db_pool::{AppState, HotelPool};

mod chat;
mod inventory;
mod rooms;
mod routes;
mod utils;

//Send notification on discord through webhook
pub async fn notify_discord(msg: &str) -> Result<(), reqwest::Error> {
    let payload = serde_json::json!({
        "content": msg
    });

    reqwest::Client::new()
        .post("https://discord.com/api/webhooks/1440912618205347891/Ekg89krDoPm41kA27LA3gXgNWmMWvCCtziYIUsjqaY22Jnw4a6IWhZOht0in5JjnPX-W")
        .json(&payload)
        .send()
        .await?;

    Ok(())
}

#[tokio::main(flavor = "multi_thread", worker_threads = 8)]
async fn main() -> std::io::Result<()> {
    dotenv().ok();

    //send crahs notification t odiscord webhook
    std::panic::set_hook(Box::new(|info| {
        let msg = format!("Rust panic: {}", info);
        let payload = serde_json::json!({
            "content": msg
        });
        let client = reqwest::blocking::Client::new();
        let _ = client
            .post("https://discord.com/api/webhooks/1440912618205347891/Ekg89krDoPm41kA27LA3gXgNWmMWvCCtziYIUsjqaY22Jnw4a6IWhZOht0in5JjnPX-W")
            .json(&payload)
            .send();
    }));

    //DB pools
    let logs_manager = SqliteConnectionManager::file("db/auth_copy_2.sqlite");
    let logs_pool = Pool::builder()
        .max_size(5)
        .build(logs_manager)
        .expect("Failed to build logs pool");

    let hotel_pools = HotelPool::new();
    let state = AppState {
        hotel_pools,
        logs_pool,
        ws_map: Arc::new(DashMap::new()),
    };

    let jwt_secret = env::var("JWT_SECRET")
        .expect("JWT_SECRET must be set")
        .to_string();

    let jwt_keys = JwtKeys {
        encoding: EncodingKey::from_secret(jwt_secret.as_ref()),
        decoding: DecodingKey::from_secret(jwt_secret.as_ref()),
    };

    let cors = CorsLayer::very_permissive()
        .allow_credentials(true)
        .allow_methods([Method::GET, Method::POST, Method::PUT, Method::OPTIONS])
        .allow_headers([CONTENT_TYPE, AUTHORIZATION, USER_AGENT]);
    
    //create router using entry point from "src/routes/mod.rs"
    let app = create_router(state).layer(Extension(jwt_keys)).layer(cors);

    let listener = TcpListener::bind("0.0.0.0:7080").await?;
    serve(listener, app).into_future().await?;
    Ok(())
}

