import { readFile } from "node:fs/promises";
import type { ServerResponse } from "node:http";

const CLIENT_ASSET_PREFIX = "/client/";
const VENDOR_ASSET_PREFIX = "/vendor/";
const APP_ASSET_PREFIX = "/assets/";

export function isClientAssetPath(pathname: string): boolean {
  return (
    pathname.startsWith(CLIENT_ASSET_PREFIX) ||
    pathname.startsWith(VENDOR_ASSET_PREFIX) ||
    pathname.startsWith(APP_ASSET_PREFIX)
  );
}

export async function handleClientAssetRequest(url: URL, res: ServerResponse): Promise<void> {
  const isVendorAsset = url.pathname.startsWith(VENDOR_ASSET_PREFIX);
  const isAppAsset = url.pathname.startsWith(APP_ASSET_PREFIX);
  const assetPrefix = isVendorAsset ? VENDOR_ASSET_PREFIX : isAppAsset ? APP_ASSET_PREFIX : CLIENT_ASSET_PREFIX;
  const assetName = url.pathname.slice(assetPrefix.length);

  if (!isAllowedAssetPath(assetName, isVendorAsset, isAppAsset)) {
    res.statusCode = 404;
    res.end("Not found");
    return;
  }

  try {
    const assetDirectory = isVendorAsset ? "vendor" : isAppAsset ? "assets" : "client";
    const assetUrl = new URL(`../${assetDirectory}/${assetName}`, import.meta.url);
    const source = await readFile(assetUrl);
    res.statusCode = 200;
    res.setHeader("content-type", getContentType(assetName));
    res.setHeader("cache-control", "no-cache");
    res.end(source);
  } catch {
    res.statusCode = 404;
    res.end("Not found");
  }
}

function isAllowedAssetPath(assetName: string, isVendorAsset: boolean, isAppAsset: boolean): boolean {
  if (assetName.split("/").includes("..")) {
    return false;
  }

  if (isAppAsset) {
    return /^[a-z0-9_.-]+\.(svg|png)$/i.test(assetName);
  }

  if (isVendorAsset) {
    return /^[a-z0-9/_.-]+\.(css|js|mjs|png)$/i.test(assetName);
  }

  return /^[a-z0-9-]+\.js$/i.test(assetName);
}

function getContentType(assetName: string): string {
  if (assetName.endsWith(".css")) {
    return "text/css; charset=utf-8";
  }

  if (assetName.endsWith(".png")) {
    return "image/png";
  }

  if (assetName.endsWith(".svg")) {
    return "image/svg+xml; charset=utf-8";
  }

  if (assetName.endsWith(".png")) {
    return "image/png";
  }

  return "text/javascript; charset=utf-8";
}
