/**
 * Map filesystem/storage errors into standardized ApiErrors.
 *
 * Problem:
 * - `fs.readdir()` throws ENOENT when a path does not exist.
 * - Without mapping, routes often return 500 with `error.message` (inconsistent).
 *
 * Goal:
 * - If a requested branch/year/month/day path does not exist => return 404.
 * - But if the NAS root itself is not available/misconfigured => return 500.
 *
 * This avoids:
 * - Incorrect 500s for normal “not found” cases.
 * - Misleading 404s when the whole NAS is down.
 */

import fs from "node:fs/promises";
import { ApiError } from "./errors.js";

/**
 * Check whether an error looks like a “path not found” error from Node’s fs.
 * ENOENT: No such file or directory
 * ENOTDIR: A path segment is not a directory
 *
 * @param {unknown} err
 * @returns {boolean}
 */
export function isFsNotFoundError(err) {
	return Boolean(
		err &&
			typeof err === "object" &&
			(err.code === "ENOENT" || err.code === "ENOTDIR")
	);
}

/**
 * Determine if the configured NAS root path is accessible.
 *
 * Rationale:
 * - If NAS_ROOT_PATH is missing or unreachable, “not found” below it
 *   is likely a system issue => return 500 instead of 404.
 *
 * @returns {Promise<boolean>}
 */
async function isNasRootAccessible() {
	const root = process.env.NAS_ROOT_PATH;
	if (!root) return false;

	try {
		// access() succeeds if the path exists and is accessible.
		await fs.access(root);
		return true;
	} catch {
		return false;
	}
}

/**
 * Convert errors from the storage layer into ApiErrors.
 *
 * Policy:
 * - ENOENT/ENOTDIR:
 *     - If NAS root accessible => 404 FS_NOT_FOUND (requested resource missing)
 *     - Else => 500 FS_STORAGE_ERROR (system/config issue)
 * - Anything else => 500 FS_STORAGE_ERROR
 *
 * @param {unknown} err
 * @param {{
 *   notFoundCode?: string,
 *   notFoundMessage?: string,
 *   details?: any
 * }=} options
 * @returns {Promise<ApiError>}
 */
export async function mapStorageReadError(
	err,
	{ notFoundCode = "FS_NOT_FOUND", notFoundMessage = "Not found", details } = {}
) {
	if (isFsNotFoundError(err)) {
		const rootOk = await isNasRootAccessible();

		// If the NAS is not accessible, treat it as an internal failure.
		if (!rootOk) {
			return new ApiError({
				status: 500,
				code: "FS_STORAGE_ERROR",
				message: "Internal server error",
				cause: err,
			});
		}

		// NAS root exists => the specific requested path is missing => 404.
		return new ApiError({
			status: 404,
			code: notFoundCode,
			message: notFoundMessage,
			details,
			cause: err,
		});
	}

	// For all other filesystem errors, return a generic 500.
	return new ApiError({
		status: 500,
		code: "FS_STORAGE_ERROR",
		message: "Internal server error",
		cause: err,
	});
}
