mod logger;

extern crate rocket;
extern crate rocket_dyn_templates;

use rocket::response::content::RawJson;
use rocket::{get, post, launch, build, routes};
use rocket::fs::FileServer;
use rocket_dyn_templates::{Template, context};
use rocket::serde::{Deserialize, Serialize, json::Json};

use chrono::Local;

use std::borrow::Cow;
use std::io::Write;
use std::path::Path;
use std::fs::File;
use std::fs::read_to_string;

use serde_json::{Value, json};

use crate::logger::iwakulog::{LogLevel, log};

const ASSETS_DIR:       &str = "./assets";
const GUEST_MESSAGES:   &str = "./guests.json";
const DATE_TIME_FORMAT: &str = "%Y-%m%d | %H:%M";

#[derive(Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
struct GuestMessage<'r> {
    name: Cow<'r, str>,
    body: Cow<'r, str>,
}


fn check_file(path: &str) -> bool {
    Path::new(path).exists()
}

fn read_guest_messages() -> Result<Value, Box<dyn std::error::Error>> {
    let file = read_to_string(GUEST_MESSAGES)?;
    let json: Value = serde_json::from_str(&file)?;
    Ok(json)
}

fn post_guest_message(name: &str, body: &str) {
    let mut guest_json = match read_guest_messages() {
        Ok(x) => x,
        Err(x) => panic!("Error while reading guest messages: {x:?}")
    };
    let messages = guest_json["messages"]
        .as_array_mut()
        .expect("Object is not an array?");
    let date = Local::now().format(DATE_TIME_FORMAT);
    messages.push(json!({
        "name": name,
        "body": body,
        "date": date.to_string(),
    }));
    let mut file = File::create(GUEST_MESSAGES).expect("Couldn't read msgs");
    file.write_all(guest_json.to_string().as_bytes()).expect("wah");
}



#[get("/")]
fn index() -> Template {
    Template::render("index", context! {})
}

#[post("/post_message", data = "<input>")]
fn post_msg(input: Json<GuestMessage<'_>>) {
    post_guest_message(&input.name, &input.body);
    return;
}

#[get("/guestbook")]
fn guests() -> Template {
    let guest_json = match read_guest_messages() {
        Ok(x) => x,
        Err(x) => panic!("Error while reading guest messages: {x:?}")
    };
    Template::render("guest", &guest_json)
}

#[launch]
fn rocket() -> _ {
    if !check_file(GUEST_MESSAGES) {
        log(LogLevel::Warn, format!("Guest messages file ({}) has not been found. Creating a new one.", GUEST_MESSAGES).as_str());
        let mut file = File::create(GUEST_MESSAGES).expect("Failed to create file.");
        file.write_all(b"{\"messages\":[]}").expect("Failed to write to file.");
    }
    build()
        .mount("/", routes![index, guests, post_msg])
        .mount("/assets", FileServer::from(ASSETS_DIR))
        .attach(Template::fairing())
}

