import { randomUUID } from "crypto";
import { mkdir, readFile, readdir, rm, stat, writeFile } from "fs/promises";
import path from "path";
import { migrateLegacyUploads, uploadDirectory } from "@/lib/runtime/config";

const maxUploadSize = 5 * 1024 * 1024;

const allowedMimeTypes = new Map([
  ["image/jpeg", [".jpg", ".jpeg"]],
  ["image/png", [".png"]],
  ["image/webp", [".webp"]],
  ["application/pdf", [".pdf"]],
]);

export type MediaFile = {
  name: string;
  url: string;
  type: "image" | "pdf";
  extension: string;
  size: number;
  uploadedAt: string;
  isImage: boolean;
  isPdf: boolean;
};

export function getMediaMimeType(fileName: string) {
  const extension = path.extname(fileName).toLowerCase();
  if (extension === ".jpg" || extension === ".jpeg") return "image/jpeg";
  if (extension === ".png") return "image/png";
  if (extension === ".webp") return "image/webp";
  if (extension === ".pdf") return "application/pdf";
  return "";
}

export async function ensureUploadDirectory() {
  await mkdir(uploadDirectory, { recursive: true });
  const probe = path.join(uploadDirectory, `.write-check-${Date.now()}`);
  await writeFile(probe, "ok", "utf8");
  await rm(probe, { force: true });
}

export function validateUpload(file: File) {
  const extensions = allowedMimeTypes.get(file.type);
  const extension = path.extname(file.name).toLowerCase();

  if (!extensions || !extensions.includes(extension)) {
    return "Bitte eine JPG-, PNG-, WebP- oder PDF-Datei hochladen.";
  }

  if (file.size <= 0) {
    return "Die Datei ist leer.";
  }

  if (file.size > maxUploadSize) {
    return "Die Datei darf maximal 5 MB groß sein.";
  }

  return "";
}

export function createSafeUploadName(originalName: string) {
  const extension = path.extname(originalName).toLowerCase();
  const rawBaseName = path.basename(originalName, extension);
  const safeBaseName = rawBaseName
    .toLowerCase()
    .normalize("NFKD")
    .replace(/[\u0300-\u036f]/g, "")
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-+|-+$/g, "")
    .slice(0, 80) || "upload";

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

export function resolveUploadTarget(fileName: string) {
  const target = path.resolve(uploadDirectory, fileName);
  const uploadRoot = path.resolve(uploadDirectory);

  if (!target.startsWith(`${uploadRoot}${path.sep}`)) {
    throw new Error("Ungültiger Upload-Pfad.");
  }

  return target;
}

function isAllowedStoredFile(fileName: string) {
  const extension = path.extname(fileName).toLowerCase();
  const allowedExtensions = [...allowedMimeTypes.values()].flat();
  return !fileName.startsWith(".") && allowedExtensions.includes(extension);
}

export async function listMediaFiles(): Promise<MediaFile[]> {
  await migrateLegacyUploads();
  await mkdir(uploadDirectory, { recursive: true });
  const entries = await readdir(uploadDirectory);
  const visibleEntries = entries.filter(isAllowedStoredFile);
  const files = await Promise.all(visibleEntries.map(async (entry) => {
    const fileStat = await stat(path.join(uploadDirectory, entry));
    const extension = path.extname(entry).toLowerCase();
    const isImage = [".jpg", ".jpeg", ".png", ".webp"].includes(extension);
    const isPdf = extension === ".pdf";

    return {
      name: entry,
      url: `/api/media/${encodeURIComponent(entry)}`,
      type: isPdf ? "pdf" as const : "image" as const,
      extension: extension.replace(".", "").toUpperCase() || "Datei",
      size: fileStat.size,
      uploadedAt: fileStat.birthtime.toISOString(),
      isImage,
      isPdf,
    };
  }));

  return files.sort((left, right) => right.uploadedAt.localeCompare(left.uploadedAt));
}

export async function saveMediaFile(file: File) {
  const error = validateUpload(file);
  if (error) return { error };

  await ensureUploadDirectory();
  const safeName = createSafeUploadName(file.name);
  const target = resolveUploadTarget(safeName);
  await writeFile(target, Buffer.from(await file.arrayBuffer()));

  return { fileName: safeName };
}

export async function readMediaFile(fileName: string) {
  if (!isAllowedStoredFile(fileName) || path.basename(fileName) !== fileName) {
    return null;
  }

  const mimeType = getMediaMimeType(fileName);
  if (!mimeType) return null;

  const target = resolveUploadTarget(fileName);

  try {
    const [data, fileStat] = await Promise.all([readFile(target), stat(target)]);
    return { data, mimeType, size: fileStat.size, uploadedAt: fileStat.birthtime.toISOString() };
  } catch {
    return null;
  }
}

export async function deleteMediaFile(fileName: string) {
  if (!isAllowedStoredFile(fileName) || path.basename(fileName) !== fileName) {
    return { error: "Ungültiger Dateiname." };
  }

  await rm(resolveUploadTarget(fileName), { force: true });
  return {};
}
