use std::net::IpAddr;

use anyhow::Result;
use log::*;
use trillium::Handler;
use trillium_forwarding::Forwarding;

use crate::{
    cdn::bunny_headers,
    fixups::{fix_location_headers, fixup_paths},
    logging::startup_log,
    options::{CDN, ServerOptions},
    server_info::server_info,
    site::SiteEngine,
};

pub fn run_server(options: &'static ServerOptions) -> Result<()> {
    let mut handlers = Vec::new();
    add_handler(&mut handlers, startup_log());
    add_handler(&mut handlers, fixup_paths());
    add_handler(&mut handlers, server_info(options));
    add_handler(
        &mut handlers,
        if options.trust_proxy {
            warn!("blindly trusting all proxy headers");
            Forwarding::trust_always()
        } else {
            Forwarding::trust_fn(IpAddr::is_loopback)
        },
    );
    match options.cdn {
        Some(CDN::Bunny) => add_handler(&mut handlers, bunny_headers(options)),
        _ => (),
    };

    add_handler(
        &mut handlers,
        SiteEngine::create(&options.content_root, &options.manifest_path()),
    );
    add_handler(&mut handlers, fix_location_headers(options));

    trillium_smol::config()
        .with_port(options.port)
        .with_host(&options.bind_host)
        .run(handlers);

    Ok(())
}

fn add_handler<H: Handler>(handlers: &mut Vec<Box<dyn Handler>>, handler: H) {
    handlers.push(Box::new(handler))
}
