// MARK: Imports
import path from 'node:path';
import fs from 'node:fs';
import ChildProcess from 'child_process';

import __path from './handlers/path.js';
import log from './handlers/log.js';
//import db from './handlers/db.js';
import config from './handlers/config.js';

// Express & more
import express from 'express';
import helmet from 'helmet';
import fileUpload from 'express-fileupload';
import bodyParser from 'body-parser';
import { Eta, Options } from 'eta';

import routes from './routes/index.js';

// MARK: Express
const app = express();

// Versioning
try {
	const rawPkg = fs.readFileSync('package.json', 'utf8');
	const pkgJson = JSON.parse(rawPkg);
	app.locals.version = pkgJson.version;
} catch (error) {
	log.core.error('Failed to get version from package.json.');
	app.locals.version = '0.0.0';
}

try {
	app.locals.versionRevLong = ChildProcess.execSync('git rev-parse HEAD').toString().trim();
	app.locals.versionRev = app.locals.versionRevLong.substring(0, 7);
} catch (error) {
	log.core.error('Failed to get git revision hash.');
	app.locals.versionRev = '0';
	app.locals.versionRevLong = '0';
}

try {
	app.locals.versionRevLatest = ChildProcess.execSync('git ls-remote --refs -q').toString().trim().split('\t')[0];
} catch (error) {
	log.core.error('Failed to get latest git revision hash.');
	app.locals.versionRevLatest = '0';
}

app.locals.versionUpdateAvailable = false;
if (app.locals.versionRevLong === app.locals.versionRevLatest) {
	log.core.info(`Running Latest Version (${app.locals.versionRevLong}; ${app.locals.version})`);
} else {
	log.core.info(`Running Version: ${app.locals.versionRevLong}; ${app.locals.version} (Latest: ${app.locals.versionRevLatest})`);
	app.locals.versionUpdateAvailable = true;
}

// ETA Init
const eta = new Eta({ views: path.join(__path, 'views') });
app.engine('eta', buildEtaEngine());
app.set('view engine', 'eta');

// MARK: Express Middleware & Config
app.set('x-powered-by', false); // helmet does this too. But not in devmode
if (!config.global.devmode && config.global.http.enable_csp) {
	app.use(
		helmet({
			strictTransportSecurity: config.global.http.enable_hsts,
			contentSecurityPolicy: {
				useDefaults: false,
				directives: {
					defaultSrc: ["'self'"],
					scriptSrc: ["'self'", config.global.http.domain],
					objectSrc: ["'none'"],
					upgradeInsecureRequests: config.global.devmode ? null : []
				}
			}
		})
	); // Add headers
}

app.use(fileUpload({ useTempFiles: false, debug: config.global.devmode_fileupload }));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

app.use(routes);

// TODO: Remove hardcoded http
app.listen(config.global.http.port, config.global.http.listen_address, () => {
	log.web.info(`Listening at http://${config.global.http.listen_address}:${config.global.http.port}`);
});

log.core.trace('Running from path: ' + __path);
config.global.devmode && log.core.error('DEVMODE ACTIVE! Do NOT use this in prod! (silly/trace/debug logging enabled, test route enabled, security features disabled )');
config.global.devmode_fileupload && log.core.error('DEVMODE ACTIVE! Do NOT use this in prod! (express-fileupload debug mode)');


// MARK: Helper Functions
function buildEtaEngine() {
	return (path: string, opts: Options, callback: CallableFunction) => {
		try {
			const fileContent = eta.readFile(path);
			const renderedTemplate = eta.renderString(fileContent, opts);
			callback(null, renderedTemplate);
		} catch (error) {
			callback(error);
		}
	};
}
