import "server-only";

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

import {
  convertVideoFormat,
  extractVideoMetadata,
  getVideoFormatDefinition,
  isConversionQualityPreset,
  isVideoOutputFormat
} from "@/lib/media-processing";
import { createErrorResponse } from "@/lib/server";
import { MediaProcessingError } from "@/lib/server/media-errors";
import { cleanupFiles, writeUploadToTemp } from "@/lib/uploads";
import { validateVideoUploadFile } from "@/lib/validations";
import type { ConversionQualityPreset, VideoOutputFormat } from "@/types/media-processing";

export const runtime = "nodejs";

function parseOutputFormat(rawValue: FormDataEntryValue | null): VideoOutputFormat {
  if (typeof rawValue === "string" && isVideoOutputFormat(rawValue)) {
    return rawValue;
  }

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

function parsePreset(rawValue: FormDataEntryValue | null): ConversionQualityPreset {
  if (typeof rawValue === "string" && isConversionQualityPreset(rawValue)) {
    return rawValue;
  }

  throw new MediaProcessingError({
    message: "Unsupported quality preset.",
    code: "invalid_input",
    statusCode: 400
  });
}

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 outputFormat = parseOutputFormat(formData.get("format"));
    const preset = parsePreset(formData.get("preset"));

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

    const sourceMetadata = await extractVideoMetadata(uploadedFile.tempPath, uploadedFile.originalName);
    const preserveAudio = sourceMetadata.hasAudio;
    const conversionResult = await convertVideoFormat({
      inputPath: uploadedFile.tempPath,
      outputFormat,
      preset,
      preserveAudio
    });
    outputPath = conversionResult.outputPath;

    const outputBuffer = await fs.readFile(conversionResult.outputPath);
    const formatDefinition = getVideoFormatDefinition(outputFormat);
    const fileName = `${uploadedFile.safeBaseName}-${preset}.${formatDefinition.extension}`;

    return new Response(outputBuffer, {
      headers: {
        "content-type": formatDefinition.mimeType,
        "content-length": String(outputBuffer.byteLength),
        "content-disposition": `attachment; filename="${fileName}"`,
        "x-videohaus-file-name": fileName,
        "x-videohaus-format": outputFormat,
        "x-videohaus-preset": preset,
        "x-videohaus-audio-preserved": preserveAudio ? "true" : "false",
        "x-videohaus-source-duration": sourceMetadata.durationSeconds.toFixed(3),
        "cache-control": "no-store"
      }
    });
  } catch (error) {
    return createErrorResponse(error, "Failed to convert video format.");
  } finally {
    await cleanupFiles([uploadPath, outputPath]);
  }
}
