mod urn;

use std::str::FromStr;

use bempline::{variables, Document, Options};
use camino::{Utf8Path, Utf8PathBuf};
use confindent::{let_get, Confindent, Entry, Node};
use time::{format_description::well_known, OffsetDateTime};
use urn::Urn;

use crate::{markup, templated::Templated, timeparse};

pub fn main() -> ! {
	let awake_conf = Confindent::from_file(std::env::args().nth(2).unwrap()).unwrap();

	let root: Utf8PathBuf = awake_conf.child_parse("Webroot").unwrap();

	// Grab the atom config and then grab the atom template
	let atom_conf_path = std::env::args().nth(3).unwrap_or(String::from("atom.conf"));
	let mut atom_conf = Confindent::from_file(&atom_conf_path).unwrap();
	let atom = Document::from_file(
		root.clone()
			.join(atom_conf.child_value("Template").unwrap())
			.canonicalize_utf8()
			.unwrap(),
		Options::default(),
	)
	.unwrap();

	let mut changed = false;
	// Go through every feed and create the entries
	let feeds = atom_conf.children_mut("Feed");
	for feed in feeds {
		make_feed(feed, &mut changed, &root, atom.clone())
	}

	// If the atom has changed, probably because we created an ID
	// write it to disk.
	if changed {
		std::fs::write(atom_conf_path, atom_conf.to_string());
	}

	std::process::exit(0);
}

pub struct AtomFeed {
	/// Where is the atom located in the webroot. (relative to webroot)
	relpath: Utf8PathBuf,
	/// What unique ID does this Feed have?
	id: String,

	title: String,
	subtitle: String,
	updated: OffsetDateTime,
	author_name: String,
	author_email: String,

	entries: Vec<AtomEntry>,
}

pub struct AtomEntry {
	/// What file does this entry direct to? This file will be opened to inspect
	/// the frontmatter for information to fill out the entry with. It will also
	/// be used to create the link to the entry.
	relpath: Utf8PathBuf,
	/// What unique ID does this Entry have?
	id: String,

	title: String,
	published: OffsetDateTime,
	updated: OffsetDateTime,
}

/// Parses all the options of a feed and generates the build job
pub fn make_feed(feed: &mut Entry, changed: &mut bool, root: &Utf8Path, mut atom: Document) {
	let_get!(
		feed,
		relpath: Utf8PathBuf = "Output",
		clone id = "Id",
		clone title = "Title",
		clone subtitle = "Subtitle",
		clone updated = "Updated",
	);

	//FIXME: gen- We need to backresolve the feed URL
	let feed_link = "";
	let author_name = feed.get("Author/Name").unwrap().to_owned();
	let author_email = feed.get("Author/Email").unwrap().to_owned();

	let mut atomfeed = AtomFeed {
		relpath,
		id,
		title,
		subtitle,
		updated: timeparse::parse(&updated).unwrap(),
		author_name,
		author_email,
		entries: vec![],
	};

	let entries = feed.children_mut("Entry");
	for entry in entries {
		if !entry.has_child("Id") {
			//TODO: gen- Read NID from conf?
			let id = Urn::new_random("dreamy");
			entry.push_entry(("Id", id));
			*changed = true;
		}

		atomfeed.entries.push(make_entry(entry, &root));
	}
}

fn make_entry<P: AsRef<Utf8Path>>(entry: &Entry, webroot: P) -> AtomEntry {
	let relpath: Utf8PathBuf = entry.parse().unwrap();
	let path = webroot.as_ref().join(&relpath);

	let entry_content = match std::fs::read_to_string(&path) {
		Ok(ok) => ok,
		Err(e) => {
			panic!("failed to get file at {path}: {e}");
		}
	};
	let entry_templated = Templated::from_str(&entry_content).unwrap();

	let conf_or_frontmatter = |conf_key: &str, front_key: &str| -> &str {
		entry
			.child_value(conf_key)
			.unwrap_or_else(|| entry_templated.frontmatter.get(front_key).unwrap())
	};

	let title = conf_or_frontmatter("Title", "title").to_owned();
	let id = entry.child_value("Id").unwrap().to_owned();

	let entry_published_raw = conf_or_frontmatter("Published", "published");

	let updated = timeparse::parse(entry.child_value("Updated").unwrap_or_else(|| {
		entry_templated
			.frontmatter
			.get("updated")
			.unwrap_or(entry_published_raw)
	}))
	.unwrap();

	let published = timeparse::parse(entry_published_raw).unwrap();

	AtomEntry {
		relpath,
		id,
		title,
		published,
		updated,
	}
}