import "server-only";

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

import { extractFrame, extractVideoMetadata } from "@/lib/media-processing";
import { cleanupFiles, writeUploadToTemp } from "@/lib/uploads";
import { createErrorResponse } from "@/lib/server";
import { MediaProcessingError } from "@/lib/server/media-errors";
import { validateVideoUploadFile } from "@/lib/validations";
import type { FrameOutputFormat } from "@/types/media-processing";

export const runtime = "nodejs";

function parseOutputFormat(rawValue: FormDataEntryValue | null): FrameOutputFormat {
  if (rawValue === "jpg" || rawValue === "png") {
    return rawValue;
  }

  throw new MediaProcessingError({
    message: "Unsupported frame output format.",
    code: "invalid_input",
    statusCode: 400
  });
}

function parseTimestamp(rawValue: FormDataEntryValue | null) {
  const parsedValue = Number(rawValue);
  if (!Number.isFinite(parsedValue) || parsedValue < 0) {
    throw new MediaProcessingError({
      message: "Invalid frame timestamp.",
      code: "invalid_input",
      statusCode: 400
    });
  }

  return parsedValue;
}

export async function POST(request: Request) {
  let uploadPath: string | null = null;
  let outputPath: string | null = null;

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

    if (!(fileEntry instanceof File)) {
      throw new MediaProcessingError({
        message: "Missing video file.",
        code: "invalid_input",
        statusCode: 400
      });
    }

    const requestedFormat = parseOutputFormat(formData.get("format"));
    const requestedTimestamp = parseTimestamp(formData.get("timestampSeconds"));

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

    const metadata = await extractVideoMetadata(uploadedFile.tempPath, uploadedFile.originalName);
    const maxTime = Math.max(metadata.durationSeconds - 0.001, 0);
    const selectedTimestamp = Math.min(Math.max(requestedTimestamp, 0), maxTime);

    const frameResult = await extractFrame({
      inputPath: uploadedFile.tempPath,
      outputFormat: requestedFormat,
      timestampSeconds: selectedTimestamp
    });
    outputPath = frameResult.outputPath;

    const imageBuffer = await fs.readFile(frameResult.outputPath);
    const mimeType = requestedFormat === "png" ? "image/png" : "image/jpeg";
    const safeTimestamp = selectedTimestamp.toFixed(3).replace(".", "_");
    const fileName = `${uploadedFile.safeBaseName}-frame-${safeTimestamp}.${requestedFormat}`;

    return new Response(imageBuffer, {
      headers: {
        "content-type": mimeType,
        "content-length": String(imageBuffer.byteLength),
        "content-disposition": `inline; filename="${fileName}"`,
        "x-videohaus-file-name": fileName,
        "x-videohaus-width": String(metadata.width),
        "x-videohaus-height": String(metadata.height),
        "x-videohaus-timestamp": selectedTimestamp.toFixed(3),
        "cache-control": "no-store"
      }
    });
  } catch (error) {
    return createErrorResponse(error, "Failed to extract frame.");
  } finally {
    await cleanupFiles([uploadPath, outputPath]);
  }
}
