import path from "node:path";
import { walk } from "@std/fs/walk";
import "@std/dotenv/load";
import { contentType } from "@std/media-types";

const _PORT = Deno.env.get('NET_PORT');
if (!_PORT || isNaN(parseInt(_PORT))) throw new Error("No NET_PORT specified in env");
const NET_PORT = parseInt(_PORT);

const NET_HOST = Deno.env.get('NET_HOST');
if (!NET_HOST) throw new Error("No NET_HOST specified in env");

const WEB_ROOT = Deno.env.get('WEB_ROOT');
if (!WEB_ROOT) throw new Error("No WEB_ROOT specified in env");

const DIR_ROOT = path.join(Deno.cwd(), WEB_ROOT);
const FILES = (await Array.fromAsync(walk(DIR_ROOT))).filter(entry => entry.isFile).map(entry => entry.path.replaceAll(Deno.cwd(), '').replaceAll('\\', '/'));

console.log(FILES)

Deno.serve({
	hostname: NET_HOST,
	port: NET_PORT,
	onListen: addr => console.log(`Listening on http://${addr.hostname}:${addr.port}`)
}, (req, addr) => {
	const notFound = new Response("Not Found. Did you try thinking Miku?", {
		status: 404,
		statusText: "Not Found (oo-ee-oo)",
		headers: { "Content-Type": "text/plain" }
	});

	try {
		const url = new URL(req.url);

		if (req.headers.get('user-agent')?.includes("Mobile") && url.pathname == '/') url.pathname = '/mobile.html';
		else if (url.pathname == '/') url.pathname = '/index.html';

		const match = FILES.find(file => file.replace(WEB_ROOT, '') == url.pathname);

		console.log(`${addr.remoteAddr.hostname}:${addr.remoteAddr.port} ${req.method} ${url.pathname} | mapping exists: ${typeof match !== 'undefined'}`);
		return new Promise<Response>(resolve => {
			if (match) {
				Deno.readFile(path.join(Deno.cwd(), match)).then(data => {
					const headers = new Headers();

					const last = match.split('/').at(-1);
					if (last) {
						const mime = contentType(last.substring(last.indexOf('.')));
						if (mime) headers.set("Content-Type", mime);
					}

					resolve(new Response(data, { headers }));
				}).catch(reason => {
					console.error(reason);
					resolve(notFound);
				});
			} else resolve(notFound);
		});
	} catch {
		return notFound;
	}
});