import { defineConfig, type Plugin } from "vite";
import react from "@vitejs/plugin-react";
import { randomUUID } from "node:crypto";
import { existsSync } from "node:fs";
import { mkdir, writeFile } from "node:fs/promises";
import type { ServerResponse } from "node:http";
import { dirname, extname, join } from "node:path";
import { fileURLToPath } from "node:url";

const projectRoot = dirname(fileURLToPath(import.meta.url));
const maxStorageJsonBodyBytes = 260 * 1024 * 1024;

function localStorageApiPlugin(): Plugin {
  return {
    name: "nodedc-local-storage-api",
    configureServer(server) {
      server.middlewares.use(async (req, res, next) => {
        const pathname = req.url?.split("?")[0];

        if (req.method === "POST" && pathname === "/api/storage/upload") {
          try {
            const payload = await readJsonBody(req);
            const result = await saveUploadedFile(payload);
            sendJson(res, 200, result);
          } catch (error) {
            sendJson(res, 500, { error: error instanceof Error ? error.message : "Upload failed" });
          }
          return;
        }

        if (req.method === "POST" && pathname === "/api/storage/data") {
          try {
            const payload = await readJsonBody(req);
            await saveLauncherData(payload);
            sendJson(res, 200, { ok: true, url: "/storage/launcher-data.json" });
          } catch (error) {
            sendJson(res, 500, { error: error instanceof Error ? error.message : "Data save failed" });
          }
          return;
        }

        next();
      });
    },
    configurePreviewServer(server) {
      server.middlewares.use(async (req, res, next) => {
        const pathname = req.url?.split("?")[0];

        if (req.method === "POST" && pathname === "/api/storage/upload") {
          try {
            const payload = await readJsonBody(req);
            const result = await saveUploadedFile(payload);
            sendJson(res, 200, result);
          } catch (error) {
            sendJson(res, 500, { error: error instanceof Error ? error.message : "Upload failed" });
          }
          return;
        }

        if (req.method === "POST" && pathname === "/api/storage/data") {
          try {
            const payload = await readJsonBody(req);
            await saveLauncherData(payload);
            sendJson(res, 200, { ok: true, url: "/storage/launcher-data.json" });
          } catch (error) {
            sendJson(res, 500, { error: error instanceof Error ? error.message : "Data save failed" });
          }
          return;
        }

        next();
      });
    },
  };
}

async function readJsonBody(req: NodeJS.ReadableStream) {
  const chunks: Buffer[] = [];
  let totalBytes = 0;

  for await (const chunk of req) {
    const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
    totalBytes += buffer.byteLength;

    if (totalBytes > maxStorageJsonBodyBytes) {
      throw new Error("Файл слишком большой для локального mock-storage");
    }

    chunks.push(buffer);
  }

  return JSON.parse(Buffer.concat(chunks).toString("utf8"));
}

async function saveUploadedFile(payload: unknown) {
  if (!isUploadPayload(payload)) {
    throw new Error("Некорректный payload загрузки");
  }

  const match = /^data:([^;,]+)?(?:;[^,]*)?;base64,(.*)$/s.exec(payload.dataUrl);

  if (!match) {
    throw new Error("Файл должен прийти data-url с base64");
  }

  const mimeType = payload.mimeType || match[1] || "application/octet-stream";
  const storedName = buildStoredFileName(payload.fileName, mimeType);
  const fileBuffer = Buffer.from(match[2], "base64");

  await Promise.all(
    getWritableStorageRoots().map(async (storageRoot) => {
      const uploadDir = join(storageRoot, "uploads");
      await mkdir(uploadDir, { recursive: true });
      await writeFile(join(uploadDir, storedName), fileBuffer);
    })
  );

  return {
    ok: true,
    url: `/storage/uploads/${storedName}`,
    fileName: storedName,
    originalFileName: payload.fileName,
    mimeType,
  };
}

async function saveLauncherData(payload: unknown) {
  await Promise.all(
    getWritableStorageRoots().map(async (storageRoot) => {
      await mkdir(storageRoot, { recursive: true });
      await writeFile(join(storageRoot, "launcher-data.json"), `${JSON.stringify(payload, null, 2)}\n`, "utf8");
    })
  );
}

function getWritableStorageRoots() {
  const roots = [join(projectRoot, "public", "storage")];
  const distRoot = join(projectRoot, "dist");

  if (existsSync(distRoot)) {
    roots.push(join(distRoot, "storage"));
  }

  return roots;
}

function buildStoredFileName(fileName: string, mimeType: string) {
  const extension = extname(fileName) || extensionFromMimeType(mimeType);
  const rawBase = fileName.slice(0, extension ? -extension.length : undefined);
  const safeBase =
    rawBase
      .normalize("NFKD")
      .replace(/[^\w.-]+/g, "-")
      .replace(/^-+|-+$/g, "")
      .slice(0, 80) || "upload";

  return `${Date.now()}-${randomUUID().slice(0, 8)}-${safeBase}${extension.toLowerCase()}`;
}

function extensionFromMimeType(mimeType: string) {
  if (mimeType === "image/jpeg") return ".jpg";
  if (mimeType === "image/png") return ".png";
  if (mimeType === "image/gif") return ".gif";
  if (mimeType === "image/webp") return ".webp";
  if (mimeType === "video/mp4") return ".mp4";
  if (mimeType === "video/webm") return ".webm";
  if (mimeType === "video/quicktime") return ".mov";
  return "";
}

function sendJson(res: ServerResponse, statusCode: number, payload: unknown) {
  res.statusCode = statusCode;
  res.setHeader("Content-Type", "application/json; charset=utf-8");
  res.end(JSON.stringify(payload));
}

function isUploadPayload(payload: unknown): payload is { fileName: string; mimeType: string; dataUrl: string } {
  if (!payload || typeof payload !== "object") return false;

  const candidate = payload as { fileName?: unknown; mimeType?: unknown; dataUrl?: unknown };

  return typeof candidate.fileName === "string" && typeof candidate.mimeType === "string" && typeof candidate.dataUrl === "string";
}

export default defineConfig({
  plugins: [react(), localStorageApiPlugin()],
});
