use actix_cors::Cors;
use actix_files::Files;
use actix_web::http::header::{CacheControl, CacheDirective};
use actix_web::middleware;
use actix_web::web::Data;
use actix_web::{web::scope, App, HttpServer};
use log::info;

mod db;
mod jwt;
mod routes;
mod state;
mod types;
mod util;

use jwt::Authentication;
use routes::{get_comments, get_posts, login, new_comment, new_post, post_by_id, register};
use state::CaptchaState;
use state::ServerState;
#[allow(unused_imports)]
use util::hex_string;

use crate::routes::{delete_post, engage_post, get_comment_count, get_engagements};

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let mut builder = env_logger::Builder::new();
    builder
        .filter(None, log::LevelFilter::Debug)
        .filter_module("sqlx", log::LevelFilter::Warn)
        .init();

    let data = ServerState::new().await;
    let capt_db = CaptchaState::new();
    let auth = Authentication::new("secret".as_bytes());

    #[cfg(debug_assertions)]
    {
        for _ in 0..10 {
            let s = hex_string(10);
            info!("Adding captcha key: {}", &s);
            capt_db.capthca_db.lock().unwrap().insert(s);
        }
    }

    info!("Spinning up server on http://localhost:8080");
    HttpServer::new(move || {
        let cors = Cors::default()
            .allowed_origin("https://shitpost.se")
            .allowed_methods(vec!["GET", "POST"])
            .max_age(3600);

        // In debug mode, allow any origin
        #[cfg(debug_assertions)]
        let cors = cors.allow_any_origin();

        App::new()
            .wrap(cors)
            .wrap(middleware::Compress::default())
            .wrap(middleware::Logger::new("%s %r"))
            .wrap(middleware::NormalizePath::trim())
            .wrap(
                middleware::DefaultHeaders::new()
                    .add(CacheControl(vec![CacheDirective::MaxAge(31536000)])),
            )
            .service(
                scope("/api")
                    .service(get_posts)
                    .service(new_post)
                    .service(delete_post)
                    .service(new_comment)
                    .service(get_comments)
                    .service(get_comment_count)
                    .service(engage_post)
                    .service(get_engagements)
                    .service(post_by_id)
                    .service(login)
                    .service(register)
                    .app_data(Data::new(data.clone()))
                    .app_data(Data::new(capt_db.clone()))
                    .app_data(Data::new(auth.clone())),
            )
            .service(
                Files::new("/", "./public")
                    .index_file("index.html")
                    .default_handler(actix_files::NamedFile::open("./public/index.html").unwrap()),
            )
    })
    .bind("0.0.0.0:8080")?
    .run()
    .await
}