import "server-only";

import path from "node:path";

import { runFfprobeJson } from "@/lib/ffprobe/ffprobe";
import { MediaProcessingError } from "@/lib/server/media-errors";
import type { MediaStreamSummary, VideoMetadata } from "@/types/media-processing";

interface FfprobeStream {
  codec_type?: string;
  codec_name?: string;
  width?: number;
  height?: number;
  avg_frame_rate?: string;
  r_frame_rate?: string;
  duration?: string;
  channels?: number;
  sample_rate?: string;
}

interface FfprobePayload {
  format?: {
    duration?: string;
  };
  streams?: FfprobeStream[];
}

function parseFraction(fraction: string | undefined) {
  if (!fraction || fraction === "0/0") {
    return null;
  }

  if (!fraction.includes("/")) {
    const parsed = Number(fraction);
    return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
  }

  const [leftRaw, rightRaw] = fraction.split("/");
  const left = Number(leftRaw);
  const right = Number(rightRaw);

  if (!Number.isFinite(left) || !Number.isFinite(right) || right <= 0) {
    return null;
  }

  return left / right;
}

function parseStream(stream: FfprobeStream): MediaStreamSummary {
  const codecType =
    stream.codec_type === "video"
      ? "video"
      : stream.codec_type === "audio"
        ? "audio"
        : "other";

  return {
    codecType,
    codecName: stream.codec_name ?? null,
    width: stream.width ?? null,
    height: stream.height ?? null,
    frameRate: parseFraction(stream.avg_frame_rate) ?? parseFraction(stream.r_frame_rate),
    durationSeconds:
      stream.duration && Number.isFinite(Number(stream.duration))
        ? Number(stream.duration)
        : null,
    channels: stream.channels ?? null,
    sampleRate:
      stream.sample_rate && Number.isFinite(Number(stream.sample_rate))
        ? Number(stream.sample_rate)
        : null
  };
}

export async function extractVideoMetadata(
  inputPath: string,
  originalFilename?: string
): Promise<VideoMetadata> {
  const payload = await runFfprobeJson<FfprobePayload>([
    "-v",
    "error",
    "-print_format",
    "json",
    "-show_format",
    "-show_streams",
    inputPath
  ]);

  const streams = payload.streams ?? [];
  const streamSummaries = streams.map(parseStream);
  const videoStream = streamSummaries.find((stream) => stream.codecType === "video");
  const audioStream = streamSummaries.find((stream) => stream.codecType === "audio");

  if (!videoStream || !videoStream.width || !videoStream.height) {
    throw new MediaProcessingError({
      message: "No valid video stream found in uploaded file.",
      code: "invalid_file",
      statusCode: 400
    });
  }

  const formatDuration = payload.format?.duration ? Number(payload.format.duration) : NaN;
  const fallbackDuration = videoStream.durationSeconds ?? 0;
  const durationSeconds = Number.isFinite(formatDuration) ? formatDuration : fallbackDuration;

  return {
    filename: originalFilename || path.basename(inputPath),
    durationSeconds: Math.max(durationSeconds, 0),
    width: videoStream.width,
    height: videoStream.height,
    frameRate: videoStream.frameRate,
    hasAudio: Boolean(audioStream),
    videoCodec: videoStream.codecName,
    audioCodec: audioStream?.codecName ?? null,
    streams: streamSummaries
  };
}
