#![allow(dead_code)]
use std::net::SocketAddr;
use std::path::PathBuf;

use actix_files::Files;
use actix_web::{
    http::{Method, StatusCode},
    middleware::{self, ErrorHandlers},
    web, App, HttpServer,
};
use clap::Parser;
use env_logger::{Env, WriteStyle};
use handlebars::Handlebars;
use log::LevelFilter;

mod errors;
mod main_pages;
mod template_utils;

use errors::generic_error;
use main_pages::{mail_post, template};

#[derive(Parser, Debug, Clone)]
struct Config {
    #[clap(long, value_parser)]
    /// The directory from which to serve static content and
    /// handlebars templates
    template_directory: PathBuf,
    #[clap(long, default_value = "127.0.0.1:8000", value_parser)]
    /// The address on which to listen
    address: SocketAddr,
    #[clap(long, action)]
    /// Whether to start the server in dev mode; this enables some nice
    /// handlebars features that are not intended for production, and enables
    /// more verbose logs
    dev_mode: bool,
}

#[derive(Debug)]
struct SharedData<'a> {
    handlebars: Handlebars<'a>,
    config: Config,
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let config = {
        let mut config = Config::parse();
        config.template_directory = config.template_directory.canonicalize()?;
        config
    };

    env_logger::Builder::new()
        .filter_level(if config.dev_mode {
            LevelFilter::Info
        } else {
            LevelFilter::Debug
        })
        .write_style(WriteStyle::Always)
        .parse_env(
            Env::new()
                .filter("TLATERNET_LOG_LEVEL")
                .write_style("TLATERNET_LOG_STYLE"),
        )
        .init();

    let mut handlebars = Handlebars::new();
    handlebars
        .register_templates_directory(".html", config.template_directory.clone())
        .expect("templates should compile correctly");
    handlebars.set_dev_mode(config.dev_mode);

    let shared_data = web::Data::new(SharedData {
        handlebars,
        config: config.clone(),
    });

    HttpServer::new(move || {
        App::new()
            .wrap(middleware::NormalizePath::trim())
            // TODO(tlater): When actix-web 4.3 releases, this can be improved a
            // lot because of this PR:
            //
            // https://github.com/actix/actix-web/pull/2784
            .wrap(
                ErrorHandlers::new()
                    .handler(StatusCode::NOT_FOUND, generic_error)
                    .handler(StatusCode::INTERNAL_SERVER_ERROR, generic_error),
            )
            .app_data(shared_data.clone())
            .service(template)
            .service(mail_post)
            .service(Files::new("/", &config.template_directory))
            .default_service(web::route().method(Method::GET))
    })
    .bind(config.address)?
    .run()
    .await
}
