use std::fs;
use std::fs::File;
use std::path::Path;

extern crate tera;
use tera::{
	Context,
	Tera,
};

use serde::{
	Deserialize,
	Serialize,
};
#[derive(Clone, Debug, Serialize, Deserialize)]
struct SVGConfig {
	svgs: Vec<SVGMetadata>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
struct SVGMetadata {
	template: String,
	title: String,
	description: String,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
struct Post {
	full_url: Option<String>,
	url: String,
	title: String,
	summary: String,
	date_published: String,
	date_modified: Option<String>,
	template_name: String,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
struct Project {
	full_url: Option<String>,
	url: String,
	title: String,
	image: String,
	summary: String,
	template_name: String,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
struct Config {
	posts: Vec<Post>,
	tech_demos: Vec<Project>,
	projects: Vec<Project>,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
struct MyContext {
	title: String,
	description: String,
	canonical_url: String,
	favicon_image: String,
	page_image: String,

	og_type: String,
	og_locale: String,
	og_site_name: String,

	twitter_card: String,

	posts: Vec<Post>,
	tech_demos: Vec<Project>,
	projects: Vec<Project>,
}
impl Default for MyContext {
	fn default() -> Self {
		Self {
            title: "chmod777's homepage".to_owned(),
            description: "A place where chmod777 puts their blog posts, project updates, and tech demos.".to_owned(),
            canonical_url: "http://tilde.club/~chmod777".to_owned(),
            favicon_image: "http://tilde.club/~chmod777/favicon.svg".to_owned(),
            page_image: "http://tilde.club/~chmod777/favicon.svg".to_owned(),
            og_type: "website".to_owned(),
            og_locale: "en-US".to_owned(),
            og_site_name: "tilde.club".to_owned(),
            twitter_card: "summary".to_owned(),
			posts: Vec::new(),
			tech_demos: Vec::new(),
			projects: Vec::new(),
        }
	}
}
fn get_file(path: &str) -> File {
	let path = Path::new(path);
	let display = path.display();
	match File::create(path) {
		Ok(file) => file,
		Err(error) => panic!("Couldn't create file {}: {}", &display, &error),
	}
}
fn read_file(path: &str) -> String {
	fs::read_to_string(path).expect(&format!("Failed to read file: {}", path))
}
fn append_str(base: &str, extend: &str) -> String {
	let mut s = base.to_owned();
	s.push_str(extend);
	s
}
fn main() {
	{
		let svg_tera = match Tera::new("svg_templates/**/*") {
			Ok(tera) => tera,
			Err(error_s) => panic!("Parsing error(s): {}", error_s),
		};

		let svg_config_json_string = read_file("svg_config.json");
		let svg_config: SVGConfig =
			serde_json::from_str(&svg_config_json_string).unwrap();

		for metadata in svg_config.svgs.iter() {
			let temp_path = append_str("templates/svg/", &metadata.template);
			let path = append_str("public/assets/svg/", &metadata.template);

			svg_tera
				.render_to(
					&metadata.template,
					&Context::from_serialize(&metadata).unwrap(),
					get_file(&temp_path),
				)
				.unwrap();

			fs::copy(temp_path, path).unwrap();
		}
	}

	let tera = match Tera::new("templates/**/*") {
		Ok(tera) => tera,
		Err(error_s) => panic!("Parsing error(s): {}", error_s),
	};

	let config_json_string = read_file("config.json");
	let config: Config = serde_json::from_str(&config_json_string).unwrap();

	let mut context = MyContext::default();

	let base_url = "http://tilde.club/~chmod777";
	for mut post in config.posts.iter().cloned() {
		post.full_url = Some(append_str(base_url, &post.url));
		context.posts.push(post);
	}
	for mut demo in config.tech_demos.iter().cloned() {
		demo.full_url = Some(append_str(base_url, &demo.url));
		context.tech_demos.push(demo)
	}
	for mut project in config.projects.iter().cloned() {
		project.full_url = Some(append_str(base_url, &project.url));
		context.projects.push(project);
	}

	tera.render_to(
		"index.html",
		&Context::from_serialize(&context).unwrap(),
		get_file("public/index.html"),
	)
	.unwrap();

	{
		context.title = "chmod777's blog".to_owned();
		context.canonical_url = "http://tilde.club/~chmod777/blog/blog.html".to_owned();
		let blog_context = Context::from_serialize(&context).unwrap();
		tera.render_to(
			"blog/blog.html",
			&blog_context,
			get_file("public/blog/blog.html"),
		)
		.unwrap();

		tera.render_to("feed.rss", &blog_context, get_file("public/feed.rss"))
			.unwrap();

		context.og_type = "article".to_owned();
		for post in context.posts.iter() {
			context.canonical_url = post.full_url.clone().unwrap();
			context.description = post.summary.clone();

			let path = append_str("public", &post.url);
			tera.render_to(
				&post.template_name,
				&Context::from_serialize(&context).unwrap(),
				get_file(&path),
			)
			.unwrap();
		}
	}

	{
		context.title = "chmod777's projects".to_owned();
		context.og_type = "website".to_owned();
		context.canonical_url = "http://tilde.club/~chmod777/projects/projects.html".to_owned();
		context.description = "".to_owned();

		tera.render_to(
			"projects/projects.html",
			&Context::from_serialize(&context).unwrap(),
			get_file("public/projects/projects.html"),
		)
		.unwrap();

		for project in context.projects.iter() {
			context.canonical_url = project.full_url.clone().unwrap();
			context.description = project.summary.clone();

			let path = append_str("public", &project.url);
			tera.render_to(
				&project.template_name,
				&Context::from_serialize(&context).unwrap(),
				get_file(&path),
			)
			.unwrap();
		}
	}

	{
		context.title = "chmod777's tech demos".to_owned();
		context.canonical_url = "http://tilde.club/~chmod777/tech_demos/tech_demos.html".to_owned();
		context.description = "".to_owned();

		tera.render_to(
			"tech_demos/tech_demos.html",
			&Context::from_serialize(&context).unwrap(),
			get_file("public/tech_demos/tech_demos.html"),
		)
		.unwrap();

		for demo in context.tech_demos.iter() {
			context.canonical_url = demo.full_url.clone().unwrap();
			context.description = demo.summary.clone();

			let path = append_str("public", &demo.url);

			tera.render_to(
				&demo.template_name,
				&Context::from_serialize(&context).unwrap(),
				get_file(&path),
			)
			.unwrap();
		}
	}
}
