import "server-only";

import fs from "node:fs";
import os from "node:os";
import path from "node:path";

import youtubeDl from "youtube-dl-exec";

import { MediaProcessingError } from "@/lib/server/media-errors";

export type YtDlpResolutionSource = "env" | "bundle-local" | "bundled" | "path" | "fallback";

interface YtDlpBinaryResolution {
  path: string;
  source: YtDlpResolutionSource;
  triedPaths: string[];
}

function fileExists(filePath: string) {
  try {
    return fs.statSync(filePath).isFile();
  } catch {
    return false;
  }
}

function splitPathEntries(rawPath: string | undefined) {
  if (!rawPath) {
    return [];
  }

  return rawPath
    .split(path.delimiter)
    .map((entry) => entry.trim())
    .filter(Boolean);
}

function isCommandName(value: string) {
  return !value.includes(path.sep) && !value.includes("/");
}

function getExecutableName() {
  return os.platform() === "win32" ? "yt-dlp.exe" : "yt-dlp";
}

function resolveFromEnv(triedPaths: string[]): YtDlpBinaryResolution | null {
  const configuredValue = process.env.YT_DLP_PATH?.trim() || process.env.YOUTUBE_DL_PATH?.trim() || "";
  if (!configuredValue) {
    return null;
  }

  triedPaths.push(`env:${configuredValue}`);

  if (isCommandName(configuredValue)) {
    return {
      path: configuredValue,
      source: "env",
      triedPaths
    };
  }

  const candidatePath = path.isAbsolute(configuredValue)
    ? configuredValue
    : path.resolve(configuredValue);

  if (!fileExists(candidatePath)) {
    throw new MediaProcessingError({
      message: `Configured yt-dlp binary was not found at '${candidatePath}'. Update YT_DLP_PATH to a valid executable path.`,
      code: "missing_binary",
      statusCode: 503
    });
  }

  return {
    path: candidatePath,
    source: "env",
    triedPaths
  };
}

function resolveFromKnownLocations(executableName: string, triedPaths: string[]): YtDlpBinaryResolution | null {
  const runtimePlatform = os.platform();

  const localBundleCandidates = [
    path.join(process.cwd(), ".next", "standalone", "bin", runtimePlatform, executableName),
    path.join(process.cwd(), "bin", runtimePlatform, executableName),
    path.join(process.cwd(), "bin", executableName)
  ];

  for (const candidatePath of localBundleCandidates) {
    triedPaths.push(candidatePath);
    if (fileExists(candidatePath)) {
      return {
        path: candidatePath,
        source: "bundle-local",
        triedPaths
      };
    }
  }

  const bundledCandidate = path.join(process.cwd(), "node_modules", "youtube-dl-exec", "bin", executableName);
  triedPaths.push(bundledCandidate);
  if (fileExists(bundledCandidate)) {
    return {
      path: bundledCandidate,
      source: "bundled",
      triedPaths
    };
  }

  for (const directory of splitPathEntries(process.env.PATH)) {
    const candidatePath = path.join(directory, executableName);
    triedPaths.push(candidatePath);
    if (fileExists(candidatePath)) {
      return {
        path: candidatePath,
        source: "path",
        triedPaths
      };
    }
  }

  return null;
}

export function resolveYtDlpBinaryPath(): YtDlpBinaryResolution {
  const triedPaths: string[] = [];
  const executableName = getExecutableName();
  const fromEnv = resolveFromEnv(triedPaths);
  if (fromEnv) {
    return fromEnv;
  }

  const fromKnownLocations = resolveFromKnownLocations(executableName, triedPaths);
  if (fromKnownLocations) {
    return fromKnownLocations;
  }

  return {
    path: executableName,
    source: "fallback",
    triedPaths
  };
}

export function createYtDlpClient() {
  const resolved = resolveYtDlpBinaryPath();
  if (resolved.source === "fallback") {
    throw new MediaProcessingError({
      message: `Unable to find '${resolved.path}'. Set YT_DLP_PATH to an absolute binary path. Tried: ${resolved.triedPaths.join(", ")}.`,
      code: "missing_binary",
      statusCode: 503
    });
  }

  return youtubeDl.create(resolved.path);
}
