use log::*;
use trillium::{Handler, Method, Status, conn_try};

use super::SiteEngine;

#[trillium::async_trait]
impl Handler for SiteEngine {
    async fn run(&self, conn: trillium::Conn) -> trillium::Conn {
        // short-circuit unsupported methods
        match conn.method() {
            Method::Get | Method::Head => (),
            _ => (),
        };

        let pcopy = conn.path().to_string();
        let path = conn_try!(urlencoding::decode(&pcopy), conn);
        let mf = conn_try!(self.manifest().await, conn);

        if let Some((stat, loc)) = mf.find_redirect(&path) {
            debug!("found redirect {} -> {} ({})", path, loc, stat);
            conn.with_status(stat).with_response_header("location", loc)
        } else if let Some(page) = mf.find_file(&path) {
            debug!("found page at {}", &path);
            self.serve_file(&path, page, conn.with_status(Status::Ok))
                .await
        } else if let Some(fb) = mf.find_fallback(&path) {
            debug!("found fallback path for {}", &path);
            conn.with_status(Status::MovedPermanently)
                .with_response_header("location", fb.to_owned())
        } else {
            debug!("file not found");
            let conn = conn.with_status(Status::NotFound);
            if let Some(page) = mf.error_pages.get("404") {
                return self.serve_file(&path, page, conn).await;
            }
            conn
        }
    }

    async fn init(&mut self, _info: &mut trillium::Info) -> () {
        if !self.manifest_file.exists() {
            warn!(
                "manifest file {} does not exist, scanning tree",
                self.manifest_file.display()
            );
        }
        info!("serving from {}", self.root.display());

        debug!("pre-loading manifest");
        match self.manifest().await {
            Ok(_) => (),
            Err(e) => error!("{:?}", e),
        }
    }
}
