import { existsSync } from "node:fs";
import { readFile } from "node:fs/promises";
import { join } from "node:path";
import { serveStatic } from "@hono/node-server/serve-static";
import { Hono } from "hono";
import { adminRoutes } from "./admin.js";
import type { Database } from "./db/client.js";
import type { Env } from "./env.js";
import { jsonError } from "./errors.js";
import { eventsRoutes } from "./events.js";
import { publicRoutes } from "./public.js";
import { type RateLimiter, createRateLimiter } from "./rate-limit.js";

export type AppDeps = {
	db: Database;
	env: Env;
	limiter?: RateLimiter;
	dashboardDir?: string;
};

export function createApp(deps: AppDeps) {
	const limiter = deps.limiter ?? createRateLimiter();
	const app = new Hono()
		.onError((error, c) => {
			console.error(JSON.stringify({ level: "error", msg: error.message }));
			return jsonError(c, 500, "internal", "Erreur interne.");
		})
		.get("/health", (c) => c.json({ ok: true }))
		.route("/v1", publicRoutes(deps.db))
		.route("/v1", eventsRoutes(deps.db, limiter))
		.route("/v1", adminRoutes(deps.db, deps.env));

	if (deps.dashboardDir && existsSync(deps.dashboardDir)) {
		const root = deps.dashboardDir;
		app.use("/*", serveStatic({ root }));
		app.notFound(async (c) => {
			if (c.req.method === "GET" && !c.req.path.startsWith("/v1")) {
				const html = await readFile(join(root, "index.html"), "utf8");
				return c.html(html);
			}
			return jsonError(c, 404, "not_found", "Ressource introuvable.");
		});
		return app;
	}

	return app.notFound((c) =>
		jsonError(c, 404, "not_found", "Ressource introuvable."),
	);
}

export type AppType = ReturnType<typeof createApp>;
