import { Page } from "./metadata";
import generators from "./generate";

import express, { Router } from "express";
import morgan from "morgan";
import bodyParser from "body-parser";
import activitypub from "./activitypub";
import validateHttpSig from "./activitypub/middleware/http-signature";

import "reflect-metadata";
import { createConnection} from "typeorm";
import * as path from "path";
import chokidar from "chokidar";

async function generate(): Promise<Page[]> {
	generators.copy();
	generators.css();
	generators.errors();

	generators.tutorials().then(generators.rss.tutorials);

	const posts = await generators.posts();
	generators.homepage(posts);
	generators.years(posts);
	generators.rss.posts(posts)
	generators.tags(posts).then(generators.rss.tags);
	generators.archive(posts);

	return posts;
}

function watch() {
	const watcher = chokidar.watch("site/", {
		ignoreInitial: true,
	});
	watcher.on("all", (event, path) => {
		console.log(`Regenerating due to ${event} ${path}`);
		// todo: this could be smarter about not regenerating everything
		generate();
	});
}

(async () => {
	if (process.env.NODE_ENV === undefined) {
		process.env.NODE_ENV = "development";
	}

	const app = express();
	app.use(morgan("dev"));
	app.use(bodyParser.json({ type: "application/activity+json" }));

	const connection = await createConnection({
		"type": "postgres",
		"host": process.env.DB_HOST || "localhost",
		"port": process.env.DB_PORT ? parseInt(process.env.DB_PORT) : 5432,
		"username": process.env.DB_USERNAME || "blog",
		"password": process.env.DB_PASSWORD || "blog",
		"database": process.env.DB_DATABASE || "blog",
		"synchronize": true,
		"logging": true,
		"entities": [
			path.join(__dirname, "entity/**/*.{ts,js}")
		],
		"migrations": [
			path.join(__dirname, "migration/**/*.{ts,js}")
		],
		"subscribers": [
			path.join(__dirname, "subscriber/**/*.{ts,js}")
		],
		"cli": {
			"entitiesDir": "lib/entity",
			"migrationsDir": "lib/migration",
			"subscribersDir": "lib/subscriber"
		}
	});

	const posts = await generate();
	
	if (process.env.NODE_ENV === "development") {
		watch();
	}

	await activitypub.articles.setup(posts);

	const apRouter = Router();
	apRouter.use(validateHttpSig);
	await activitypub.actor(apRouter);
	activitypub.comments(apRouter);
	activitypub.followers(apRouter);
	activitypub.inbox(apRouter);
	await activitypub.nodeinfo(apRouter);
	activitypub.webfinger(apRouter);
	activitypub.articles.route(apRouter);
	app.use(apRouter);
	app.use(express.static("out"));

	// redirect posts with changed permalinks
	for (const post of posts) {
		if (post.metadata.oldPermalink) {
			app.get(post.metadata.oldPermalink, (req, res) => {
				res.status(301).redirect(post.metadata.permalink);
			});
		}
	}

	app.use((err, req, res, next) => {
		console.error("Unhandled error:", err);
		res.status(500).sendFile("500.html", {
			root: "out"
		});
	});
	app.use((req, res, next) => {
		res.status(404).sendFile("404.html", {
			root: "out"
		});
	});

	const port = process.env.PORT || 8083;
	app.listen(port, async () => {
		console.log(`Listening on port ${port}`);

		const toFederate = await activitypub.articles.toFederate();
		activitypub.federate(toFederate);
	});
})();

