import { promises as fs } from "node:fs";
import path from "node:path";
import { NextResponse } from "next/server";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";

type IslandManifest = {
  entryAssetPath: string | null;
  wasmAssetPath: string | null;
  assetPaths: string[];
  generatedRootPath: string | null;
};

const GENERATED_ROOT = path.resolve(
  process.cwd(),
  "..",
  "rust",
  "spikes",
  "leptos-tiptap-spike",
  "generated",
  "island",
);
const ENTRY_ASSET_PATTERN = /^mnote-leptos-tiptap-spike-island\.js$/;
const WASM_PATTERN = /^mnote-leptos-tiptap-spike-island_bg\.wasm$/;

function toPosixPath(value: string): string {
  return value.split(path.sep).join("/");
}

function sanitizeRelativePath(asset: string[]): string | null {
  if (!Array.isArray(asset) || asset.length === 0) {
    return null;
  }
  const decoded = asset.map((segment) => decodeURIComponent(segment));
  const joined = decoded.join("/");
  if (!joined || joined.includes("\0")) {
    return null;
  }
  const normalized = path.posix.normalize(joined);
  if (normalized === "." || normalized.startsWith("../") || normalized.includes("/../")) {
    return null;
  }
  return normalized;
}

async function walkFiles(rootDir: string): Promise<string[]> {
  const output: string[] = [];
  const queue: string[] = [rootDir];

  while (queue.length > 0) {
    const current = queue.shift();
    if (!current) {
      continue;
    }
    const entries = await fs.readdir(current, { withFileTypes: true });
    for (const entry of entries) {
      const absolute = path.join(current, entry.name);
      if (entry.isDirectory()) {
        queue.push(absolute);
        continue;
      }
      if (!entry.isFile()) {
        continue;
      }
      const relative = path.relative(rootDir, absolute);
      output.push(toPosixPath(relative));
    }
  }

  return output.sort((a, b) => a.localeCompare(b));
}

async function buildIslandManifest(): Promise<IslandManifest> {
  const files = await walkFiles(GENERATED_ROOT);
  const entryAssetPath = files.find((item) => ENTRY_ASSET_PATTERN.test(path.posix.basename(item))) ?? null;
  const wasmAssetPath = files.find((item) => WASM_PATTERN.test(path.posix.basename(item))) ?? null;
  const generatedRootPath = entryAssetPath ? path.posix.dirname(entryAssetPath) : null;
  const assetPaths = files.filter((item) => {
    const basename = path.posix.basename(item);
    return (
      basename.endsWith(".js") ||
      basename.endsWith(".wasm") ||
      basename.endsWith(".css") ||
      basename.endsWith(".json")
    );
  });

  return {
    entryAssetPath,
    wasmAssetPath,
    assetPaths,
    generatedRootPath,
  };
}

function guessContentType(absolutePath: string): string {
  const extension = path.extname(absolutePath).toLowerCase();
  if (extension === ".js" || extension === ".mjs") {
    return "application/javascript; charset=utf-8";
  }
  if (extension === ".wasm") {
    return "application/wasm";
  }
  if (extension === ".json") {
    return "application/json; charset=utf-8";
  }
  if (extension === ".html") {
    return "text/html; charset=utf-8";
  }
  if (extension === ".css") {
    return "text/css; charset=utf-8";
  }
  return "application/octet-stream";
}

export async function GET(
  _request: Request,
  context: { params: Promise<{ asset?: string[] }> },
) {
  const params = await context.params;
  const asset = params.asset ?? [];

  if (asset.length === 1 && asset[0] === "manifest.json") {
    try {
      const manifest = await buildIslandManifest();
      return NextResponse.json(manifest, {
        headers: { "Cache-Control": "no-store" },
      });
    } catch (error) {
      return NextResponse.json(
        {
          error: "无法生成 leptos-tiptap island 清单",
          detail: error instanceof Error ? error.message : "unknown",
        },
        { status: 500 },
      );
    }
  }

  const relativePath = sanitizeRelativePath(asset);
  if (!relativePath) {
    return NextResponse.json({ error: "非法 island 资源路径" }, { status: 400 });
  }

  const absolutePath = path.resolve(GENERATED_ROOT, relativePath);
  if (!absolutePath.startsWith(GENERATED_ROOT + path.sep)) {
    return NextResponse.json({ error: "越界访问 island 资源被拒绝" }, { status: 403 });
  }

  try {
    const fileContent = await fs.readFile(absolutePath);
    return new NextResponse(fileContent, {
      status: 200,
      headers: {
        "Content-Type": guessContentType(absolutePath),
        "Cache-Control": "no-store",
      },
    });
  } catch (error) {
    if ((error as NodeJS.ErrnoException)?.code === "ENOENT") {
      return NextResponse.json({ error: "island 资源不存在" }, { status: 404 });
    }
    return NextResponse.json(
      {
        error: "读取 island 资源失败",
        detail: error instanceof Error ? error.message : "unknown",
      },
      { status: 500 },
    );
  }
}
