import { exists, readdir, stat } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { zValidator } from "@hono/zod-validator";
import { Hono } from "hono";
import { createHTTPException } from "@/lib/errors";
import type { ExtendHonoEnv } from "@/lib/types";
import type { Directory } from "@/models";
import { API, Path } from "@/models";
import { OnboardService } from "@/services/onboard";

type OnboardRouterEnv = {
	needsOnboarding: boolean;
};

const OnboardRouter = new Hono<ExtendHonoEnv<OnboardRouterEnv>>()

	.use((c, next) => {
		const service = c.get("service");
		const onboardService = service.get(OnboardService);
		c.set("needsOnboarding", onboardService.getNeedsOnboarding());
		return next();
	})
	.get("/status", (c) => {
		return c.json<API.OnboardStatusOutput>({
			needsOnboarding: c.get("needsOnboarding"),
		});
	})
	.use((c, next) => {
		if (!c.get("needsOnboarding")) {
			throw createHTTPException(403, "You cannot access this resource");
		}
		return next();
	})
	.post("/folder", zValidator("json", Path), async (c) => {
		const body = c.req.valid("json");
		try {
			if (body.path.length === 0) {
				if (os.platform() === "linux") {
					try {
						const drives = await readdir("/", { withFileTypes: true });
						return c.json<Directory[]>(
							drives
								.filter((path) => path.isDirectory())
								.map((value) => ({
									name: `/${value.name}`,
									type: "FOLDER",
								})),
						);
					} catch (_) {
						return c.json<Directory[]>([]);
					}
				}
			}
			// On Linux, ensure path starts with / for absolute paths
			const inputPath =
				os.platform() === "linux"
					? path.join("/", ...body.path)
					: path.join(...body.path);
			if (!(await exists(inputPath))) {
				throw createHTTPException(404, `Path does not exit: ${body.path}`);
			}

			const stats = await stat(inputPath);
			if (!stats.isDirectory()) {
				throw createHTTPException(400, `Path is not directory: ${inputPath}`);
			}

			const directories = await readdir(inputPath, { withFileTypes: true });
			const filtered = directories
				.filter((v) => v.isDirectory())
				.map((value): Directory => ({ name: value.name, type: "FOLDER" }));
			return c.json<Directory[]>(filtered);
		} catch (error) {
			if (error instanceof Error) {
				const nodeError = error as NodeJS.ErrnoException;

				// Access denied / Permission denied
				if (nodeError.code === "EACCES" || nodeError.code === "EPERM") {
					throw createHTTPException(
						500,
						`Access denied: You don't have permission to access this directory`,
					);
				}

				// Path not found
				if (nodeError.code === "ENOENT") {
					throw createHTTPException(
						500,
						"Directory not found: The specified path does not exist",
					);
				}

				// Path too long
				if (nodeError.code === "ENAMETOOLONG") {
					throw createHTTPException(500, "Path is too long");
				}

				// Not a directory
				if (nodeError.code === "ENOTDIR") {
					throw createHTTPException(
						500,
						"Not a directory: The path is not a valid directory",
					);
				}

				// Too many symbolic links
				if (nodeError.code === "ELOOP") {
					throw createHTTPException(
						500,
						"Too many symbolic links: Unable to resolve the path",
					);
				}

				// Input/output error
				if (nodeError.code === "EIO") {
					throw createHTTPException(
						500,
						"I/O error: Unable to read from the filesystem",
					);
				}

				// Re-throw the original error message if it's already formatted
				throw createHTTPException(500, "Failed processing your request");
			}

			// Unknown error
			throw createHTTPException(
				500,
				`Failed to read directory: ${error instanceof Error ? error.message : "Unknown error"}`,
			);
		}
	})

	.post(
		"/complete",
		zValidator("json", API.OnboardCompletedInput),
		async (c) => {
			const body = c.req.valid("json");
			const service = c.get("service");
			const onboardService = service.get(OnboardService);
			await onboardService.completeOnboarding(body);
			return c.json<API.OnboardCompletedOutput>({
				success: true,
				completed: true,
			});
		},
	);
export { OnboardRouter };
