use std::str::FromStr;

use bempline::{variables, Document, Options};
use camino::{Utf8Path, Utf8PathBuf};
use confindent::{Confindent, Value};
use cutie::Html;
use time::format_description::well_known;

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

pub fn main() -> ! {
	let awake_conf = Confindent::from_file(std::env::args().nth(2).unwrap()).unwrap();
	let atom_conf_path = std::env::args().nth(3).unwrap_or(String::from("atom.conf"));

	let atom_conf = Confindent::from_file(atom_conf_path).unwrap();

	let root: Utf8PathBuf = awake_conf.child_parse("Webroot").unwrap();
	let atom = Document::from_file(
		root.clone()
			.join(atom_conf.child_value("Template").unwrap())
			.canonicalize_utf8()
			.unwrap(),
		Options::default(),
	)
	.unwrap();

	let feeds = atom_conf.children("Feed");
	for feed in feeds {
		make_feed(feed, &root, atom.clone())
	}

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

pub fn make_feed(feed: &Value, root: &Utf8Path, mut atom: Document) {
	let feed_relout: Utf8PathBuf = feed.child_parse("Output").unwrap();
	let feed_link = feed.child_owned("Link").unwrap();
	let feed_id = feed.child_owned("Id").unwrap();
	let feed_title = feed.child_owned("Title").unwrap();
	let feed_subtitle = feed.child_owned("Subtitle").unwrap();
	let feed_updated = feed.child_owned("Updated").unwrap();
	let feed_author_name = feed.get("Author/Name").unwrap();
	let feed_author_email = feed.get("Author/Email").unwrap();

	variables!(
		atom,
		feed_link,
		feed_id,
		feed_title,
		feed_subtitle,
		feed_updated,
		feed_author_email,
		feed_author_name
	);

	let entries = feed.children("Entry");
	let entry_pattern = atom.get_pattern("entry").unwrap();
	for entry in entries {
		let entry_relpath: Utf8PathBuf = entry.parse().unwrap();
		let entry_path = root.join(&entry_relpath);

		println!("entry {entry_relpath}");

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

		let entry_title = entry
			.child_value("Title")
			.unwrap_or_else(|| entry_templated.frontmatter.get("title").unwrap());
		let entry_link = entry.child_value("Link").unwrap();
		let entry_id = entry.child_value("Id").unwrap();

		let entry_published_raw = entry
			.child_value("Published")
			.unwrap_or_else(|| entry_templated.frontmatter.get("published").unwrap());

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

		let entry_published = timeparse::parse(entry_published_raw)
			.unwrap()
			.format(&well_known::Rfc3339)
			.unwrap();

		let mut entry_content = markup::process(&entry_templated.content);

		if let Some(part_id) = entry
			.child_value("Part")
			.map(|raw| raw.strip_prefix('#'))
			.flatten()
		{
			let cutie = cutie::Html::parse(entry_content);
			let found = cutie.get_by_id(part_id).unwrap();
			entry_content = found.to_string();
		}

		let mut pattern = entry_pattern.clone();
		variables!(
			pattern,
			entry_title,
			entry_link,
			entry_id,
			entry_published,
			entry_updated
		);
		pattern.set("entry_content", cdataify(&entry_content));
		atom.set_pattern("entry", pattern);
	}

	let string = atom.compile();

	let feed_out = root.join(feed_relout);
	std::fs::write(feed_out, string).unwrap();
}

//FIXME: do NOT use this name
fn htmlspecialchars(raw: &str) -> String {
	let mut ret = String::new();

	for ch in raw.chars() {
		match ch {
			'<' => ret.push_str("&lt;"),
			'>' => ret.push_str("&gt;"),
			'&' => ret.push_str("&amp;"),
			'\'' => ret.push_str("&apos;"),
			'"' => ret.push_str("&quot;"),
			c => ret.push(c),
		}
	}

	ret
}

fn cdataify(raw: &str) -> String {
	format!("<![CDATA[{raw}]]>")
}

fn fix_links(html: &mut Html, path: Utf8PathBuf) {
	let root = match path.file_name() {
		Some(_) => path.parent().unwrap().to_owned(),
		None => path,
	};

	for tag in html.child_tags_mut() {
		if let Some(src) = tag.get_attribute("src") {
			if !src.starts_with("http") {
				todo!()
			}
		}
	}
}