import "server-only";

import { promises as fs } from "node:fs";

import { extractVideoMetadata, generateThumbnailCandidatesFoundation } from "@/lib/media-processing";
import { createErrorResponse, createSuccessResponse } from "@/lib/server";
import { cleanupFiles, writeUploadToTemp } from "@/lib/uploads";
import { validateVideoUploadFile } from "@/lib/validations";
import type { ThumbnailEnhancementOptions } from "@/types/media-processing";

export const runtime = "nodejs";

function parseBooleanFlag(rawValue: FormDataEntryValue | null) {
  if (typeof rawValue !== "string") {
    return false;
  }

  const normalizedValue = rawValue.trim().toLowerCase();
  return normalizedValue === "1" || normalizedValue === "true" || normalizedValue === "on";
}

function parseReroll(rawValue: FormDataEntryValue | null) {
  const parsedValue = Number(rawValue);
  if (!Number.isFinite(parsedValue) || parsedValue < 0) {
    return 0;
  }

  return Math.floor(parsedValue);
}

function hashStringToSeed(input: string) {
  let hash = 2166136261;

  for (let index = 0; index < input.length; index += 1) {
    hash ^= input.charCodeAt(index);
    hash = Math.imul(hash, 16777619);
  }

  return hash >>> 0;
}

function formatTimestampToken(timestampSeconds: number) {
  return timestampSeconds.toFixed(3).replace(".", "_");
}

export async function POST(request: Request) {
  let uploadPath: string | null = null;
  const generatedPaths: string[] = [];

  try {
    const formData = await request.formData();
    const fileEntry = formData.get("file");

    if (!(fileEntry instanceof File)) {
      throw new Error("Missing video file.");
    }

    validateVideoUploadFile(fileEntry);
    const uploadedFile = await writeUploadToTemp(fileEntry);
    uploadPath = uploadedFile.tempPath;

    const metadata = await extractVideoMetadata(uploadedFile.tempPath, uploadedFile.originalName);
    const reroll = parseReroll(formData.get("reroll"));

    const enhancements: ThumbnailEnhancementOptions = {
      sharpen: parseBooleanFlag(formData.get("sharpen")),
      boost: parseBooleanFlag(formData.get("boost")),
      titleSafeOverlay: parseBooleanFlag(formData.get("titleSafeOverlay"))
    };

    const baseSeed = hashStringToSeed(
      `${uploadedFile.originalName}:${uploadedFile.sizeBytes}:${metadata.durationSeconds.toFixed(3)}:${uploadedFile.extension}`
    );
    const effectiveSeed = (baseSeed + Math.imul(reroll, 0x9e3779b9)) >>> 0;

    const generationResult = await generateThumbnailCandidatesFoundation({
      inputPath: uploadedFile.tempPath,
      durationSeconds: metadata.durationSeconds,
      candidateCount: 4,
      sampleCount: 18,
      seed: effectiveSeed,
      enhancements
    });

    generatedPaths.push(...generationResult.generatedPaths);

    const candidatePayload = await Promise.all(
      generationResult.candidates.map(async (candidate, index) => {
        const frameBuffer = await fs.readFile(candidate.outputPath);
        const dataUrl = `data:image/jpeg;base64,${frameBuffer.toString("base64")}`;
        const fileName = `${uploadedFile.safeBaseName}-thumbnail-${index + 1}-${formatTimestampToken(candidate.timestampSeconds)}.jpg`;

        return {
          id: candidate.id,
          timestampSeconds: candidate.timestampSeconds,
          score: candidate.score,
          rationale: candidate.rationale,
          fileName,
          dataUrl
        };
      })
    );

    return createSuccessResponse({
      metadata,
      reroll,
      seed: generationResult.seed,
      enhancements,
      candidates: candidatePayload
    });
  } catch (error) {
    return createErrorResponse(error, "Failed to generate thumbnail candidates.");
  } finally {
    await cleanupFiles([uploadPath, ...generatedPaths]);
  }
}
