/**
 * Social Media Video Downloader using multiple packages
 * Supports: Instagram, YouTube, TikTok, Twitter/X, Facebook
 *
 * - @vreden/youtube_scraper: YouTube (video/audio with quality options)
 * - snapsave-media-downloader: Instagram, TikTok, Twitter/X
 * - yt-dlp (global): Facebook (fallback)
 */

import { snapsave } from "snapsave-media-downloader";
import { spawn } from "child_process";
import {
  DownloadRequest,
  DownloadResponse,
  Platform,
  MediaType,
  VideoQuality,
  AudioFormat,
} from "@/types/download";

// Removed @vreden types

// ============================================
// SnapSave API response types
// ============================================
interface SnapSaveMedia {
  url?: string;
  thumbnail?: string;
  type?: "video" | "image";
  resolution?: string;
  shouldRender?: boolean;
}

interface SnapSaveData {
  description?: string;
  preview?: string;
  media?: SnapSaveMedia[];
}

interface SnapSaveResponse {
  success: boolean;
  data?: SnapSaveData;
  message?: string;
}

// ============================================
// yt-dlp video info type
// ============================================
interface YtDlpVideoInfo {
  id?: string;
  title?: string;
  uploader?: string;
  uploader_id?: string;
  thumbnail?: string;
  duration?: number;
  duration_string?: string;
  view_count?: number;
  like_count?: number;
  description?: string;
  formats?: YtDlpFormat[];
  url?: string;
}

interface YtDlpFormat {
  format_id?: string;
  format_note?: string;
  ext?: string;
  url?: string;
  acodec?: string;
  vcodec?: string;
  width?: number;
  height?: number;
  filesize?: number;
  abr?: number;
}

// ============================================
// Platform Detection
// ============================================

/**
 * Detects the platform from a URL
 */
export function detectPlatform(url: string): Platform {
  try {
    const urlObj = new URL(url);
    const hostname = urlObj.hostname.toLowerCase().replace(/^www\./, "");

    if (
      hostname === "youtube.com" ||
      hostname === "youtu.be" ||
      hostname.includes("youtube")
    ) {
      return "youtube";
    }

    if (
      hostname === "instagram.com" ||
      hostname.includes("instagram")
    ) {
      return "instagram";
    }

    if (
      hostname === "tiktok.com" ||
      hostname.includes("tiktok")
    ) {
      return "tiktok";
    }

    if (
      hostname === "twitter.com" ||
      hostname === "x.com" ||
      hostname.includes("twitter")
    ) {
      return "twitter";
    }

    if (
      hostname === "facebook.com" ||
      hostname.includes("facebook") ||
      hostname === "fb.watch"
    ) {
      return "facebook";
    }

    return "unknown";
  } catch {
    return "unknown";
  }
}

// ============================================
// Helper Functions
// ============================================

/**
 * Detects media type from URL
 */
function detectMediaType(url: string): MediaType {
  const lowerUrl = url.toLowerCase();
  if (
    lowerUrl.includes(".mp4") ||
    lowerUrl.includes(".webm") ||
    lowerUrl.includes(".mkv") ||
    lowerUrl.includes("video")
  ) {
    return "video";
  }
  if (
    lowerUrl.includes(".mp3") ||
    lowerUrl.includes(".m4a") ||
    lowerUrl.includes(".wav") ||
    lowerUrl.includes("audio")
  ) {
    return "audio";
  }
  if (
    lowerUrl.includes(".jpg") ||
    lowerUrl.includes(".jpeg") ||
    lowerUrl.includes(".png") ||
    lowerUrl.includes(".gif") ||
    lowerUrl.includes(".webp")
  ) {
    return "image";
  }
  return "video"; // Default to video
}

/**
 * Gets file extension from URL
 */
function getFileExtension(url: string, mediaType?: string): string {
  const lowerUrl = url.toLowerCase();
  if (lowerUrl.includes(".mp4")) return ".mp4";
  if (lowerUrl.includes(".webm")) return ".webm";
  if (lowerUrl.includes(".mkv")) return ".mkv";
  if (lowerUrl.includes(".mp3")) return ".mp3";
  if (lowerUrl.includes(".m4a")) return ".m4a";
  if (lowerUrl.includes(".jpg") || lowerUrl.includes(".jpeg")) return ".jpg";
  if (lowerUrl.includes(".png")) return ".png";
  if (lowerUrl.includes(".gif")) return ".gif";
  if (lowerUrl.includes(".webp")) return ".webp";
  
  if (mediaType === "image") return ".jpg";
  if (mediaType === "audio") return ".mp3";
  return ".mp4";
}

/**
 * Maps VideoQuality to numeric value for filtering
 */
function getQualityNumber(quality?: VideoQuality): number {
  if (!quality || quality === "max") return 1080;
  return parseInt(quality);
}

/**
 * Run yt-dlp command and get JSON output
 */
async function runYtdlp(url: string, args: string[] = []): Promise<YtDlpVideoInfo> {
  return new Promise((resolve, reject) => {
    const defaultArgs = [
      "--dump-single-json",
      "--no-warnings",
      "--no-check-certificates",
      "--prefer-free-formats",
    ];

    const allArgs = [...defaultArgs, ...args, url];

    console.log("[YT-DLP] Running command: yt-dlp", allArgs.join(" "));

    const process = spawn("yt-dlp", allArgs);

    let stdout = "";
    let stderr = "";

    process.stdout.on("data", (data) => {
      stdout += data.toString();
    });

    process.stderr.on("data", (data) => {
      stderr += data.toString();
    });

    process.on("close", (code) => {
      if (code !== 0) {
        console.error("[YT-DLP] Error:", stderr);
        reject(new Error(stderr || `yt-dlp exited with code ${code}`));
        return;
      }

      try {
        const info = JSON.parse(stdout) as YtDlpVideoInfo;
        resolve(info);
      } catch (parseError) {
        reject(new Error("Failed to parse yt-dlp output"));
      }
    });

    process.on("error", (error) => {
      console.error("[YT-DLP] Spawn error:", error);
      reject(error);
    });
  });
}

// ============================================
/**
 * Download YouTube video via yt-dlp
 */
async function downloadYoutubeVideo(
  url: string,
  quality?: VideoQuality
): Promise<DownloadResponse> {
  console.log("[YT-DLP-YOUTUBE] Downloading video:", url, "Quality:", quality);

  try {
    const targetHeight = getQualityNumber(quality);
    const info = await runYtdlp(url);

    // Find formats that have BOTH video and audio mixed into a single MP4 file.
    // yt-dlp lists these as having vcodec and acodec
    const videoFormats = info.formats?.filter(
      (f: YtDlpFormat) => 
        f.url && 
        f.ext === "mp4" && 
        f.vcodec !== "none" && 
        f.acodec !== "none" &&
        !f.url.includes(".m3u8") &&
        !f.url.includes("/manifest/")
    );

    if (!videoFormats?.length) {
      return {
        success: false,
        error: {
          code: "error.download.no_result",
          message: "Uygun video formatı bulunamadı.",
        },
      };
    }

    // Sort to find the requested quality or closest lower quality
    const sortedFormats = videoFormats.sort((a, b) => (b.height || 0) - (a.height || 0));
    
    let bestFormat = sortedFormats.find(f => (f.height || 0) <= targetHeight) || sortedFormats[0];

    // Some 1080p combined might not exist (YouTube usually separates them), fallback gracefully
    if (!bestFormat) {
       bestFormat = sortedFormats[0];
    }

    const safeTitle = info.title?.replace(/[^a-zA-Z0-9ğüşıöçĞÜŞİÖÇ\s]/g, "_") || "youtube_video";

    return {
      success: true,
      data: {
        downloadUrl: bestFormat.url!,
        filename: `${safeTitle}.mp4`,
        platform: "youtube",
        title: info.title,
        thumbnail: info.thumbnail,
        mediaType: "video",
        duration: info.duration_string,
        author: info.uploader,
        views: info.view_count?.toString(),
      },
    };
  } catch (error) {
    console.error("[YT-DLP-YOUTUBE] Video download error:", error);
    return {
      success: false,
      error: {
        code: "error.download.failed",
        message: error instanceof Error ? error.message : "YouTube video indirme hatası",
      },
    };
  }
}

/**
 * Download YouTube audio via yt-dlp
 */
async function downloadYoutubeAudio(
  url: string,
  format?: AudioFormat,
  bitrate?: string
): Promise<DownloadResponse> {
  console.log("[YT-DLP-YOUTUBE] Downloading audio:", url, "Bitrate:", bitrate);

  try {
    const targetBitrate = bitrate ? parseInt(bitrate) : 128;
    const info = await runYtdlp(url);

    // Find audio-only formats (m4a or webm/mp3 usually without vcodec)
    const audioFormats = info.formats?.filter(
      (f: YtDlpFormat) => 
        f.url && 
        f.vcodec === "none" && 
        f.acodec !== "none" && 
        (f.ext === "m4a" || f.ext === "webm") &&
        !f.url.includes(".m3u8") &&
        !f.url.includes("/manifest/")
    );

    if (!audioFormats?.length) {
      return {
        success: false,
        error: {
          code: "error.download.no_result",
          message: "Uygun ses formatı bulunamadı.",
        },
      };
    }

    // We prefer higher audio bitrate equal or closest to requested.
    const sortedFormats = audioFormats.sort((a, b) => (b.abr || 0) - (a.abr || 0));
    let bestFormat = sortedFormats.find(f => (f.abr || 0) <= targetBitrate) || sortedFormats[0];

    const safeTitle = info.title?.replace(/[^a-zA-Z0-9ğüşıöçĞÜŞİÖÇ\s]/g, "_") || "youtube_audio";
    
    // YouTube's M4A is widely supported as direct download
    const ext = bestFormat.ext || "m4a";

    return {
      success: true,
      data: {
        downloadUrl: bestFormat.url!,
        filename: `${safeTitle}.${ext}`,
        platform: "youtube",
        title: info.title,
        thumbnail: info.thumbnail,
        mediaType: "audio",
        duration: info.duration_string,
        author: info.uploader,
        views: info.view_count?.toString(),
      },
    };
  } catch (error) {
    console.error("[YT-DLP-YOUTUBE] Audio download error:", error);
    return {
      success: false,
      error: {
        code: "error.download.failed",
        message: error instanceof Error ? error.message : "YouTube ses indirme hatası",
      },
    };
  }
}

/**
 * Get YouTube video metadata without downloading via yt-dlp
 */
async function getYoutubeMetadata(url: string): Promise<YtDlpVideoInfo | null> {
  console.log("[YT-DLP-YOUTUBE] Getting metadata for:", url);

  try {
    const result = await runYtdlp(url);
    return result || null;
  } catch (error) {
    console.error("[YT-DLP-YOUTUBE] Metadata error:", error);
    return null;
  }
}

// ============================================
// Facebook Download Functions (yt-dlp fallback)
// ============================================

// Removed obsolete runYtdlp (it is moved UP)

/**
 * Download from Facebook using yt-dlp
 */
async function downloadFromFacebookYtDlp(url: string): Promise<DownloadResponse> {
  console.log("[YT-DLP] Downloading Facebook:", url);

  try {
    const info = await runYtdlp(url);

    console.log("[YT-DLP] Facebook info:", {
      title: info.title,
      uploader: info.uploader,
      duration: info.duration_string,
    });

    // Find video format with URL
    const videoFormats = info.formats?.filter(
      (f: YtDlpFormat) => f.url && (f.ext === "mp4" || f.vcodec !== "none")
    );

    if (!videoFormats?.length) {
      return {
        success: false,
        error: {
          code: "error.download.no_result",
          message: "Video formatı bulunamadı",
        },
      };
    }

    // Prefer higher quality
    const bestFormat =
      videoFormats.find(
        (f: YtDlpFormat) =>
          f.format_note?.includes("1080") || f.format_note?.includes("720")
      ) || videoFormats[0];

    const title =
      info.title?.replace(/[^a-zA-Z0-9ğüşıöçĞÜŞİÖÇ\s]/g, "_") || "facebook_video";

    return {
      success: true,
      data: {
        downloadUrl: bestFormat.url!,
        filename: `${title}.mp4`,
        platform: "facebook",
        title: info.title,
        thumbnail: info.thumbnail,
        mediaType: "video",
        duration: info.duration_string,
        author: info.uploader,
        views: info.view_count?.toString(),
      },
    };
  } catch (error) {
    console.error("[YT-DLP] Facebook error:", error);
    return {
      success: false,
      error: {
        code: "error.download.failed",
        message: error instanceof Error ? error.message : "Facebook indirme hatası",
      },
    };
  }
}

// ============================================
// SnapSave Download Functions (Instagram, TikTok, Twitter)
// ============================================

/**
 * Download using SnapSave (Instagram, TikTok, Twitter)
 */
async function downloadWithSnapSave(
  url: string,
  platform: Platform
): Promise<DownloadResponse> {
  console.log(`[SNAPSAVE] Downloading ${platform}:`, url);

  try {
    const result: SnapSaveResponse = await snapsave(url);
    console.log(`[SNAPSAVE] ${platform} result:`, JSON.stringify(result, null, 2));

    if (!result.success || !result.data?.media?.length) {
      return {
        success: false,
        error: {
          code: "error.download.no_result",
          message: result.message || "İçerik bulunamadı",
        },
      };
    }

    // Get the best quality media (prefer HD video)
    const media = result.data.media;
    let selectedMedia: SnapSaveMedia | null = null;

    // For videos, prefer HD quality
    if (media.some((m) => m.type === "video")) {
      // Sort by resolution (prefer higher quality)
      const videos = media.filter((m) => m.type === "video");

      // Prefer 1080p, then 720p, then HD, then any video
      selectedMedia =
        videos.find((m) => m.resolution?.includes("1080")) ||
        videos.find((m) => m.resolution?.includes("720")) ||
        videos.find((m) => m.resolution?.includes("HD")) ||
        videos.find((m) => !m.shouldRender) ||
        videos[0];
    } else {
      // For images, take the first one
      selectedMedia = media[0];
    }

    if (!selectedMedia?.url) {
      return {
        success: false,
        error: {
          code: "error.download.no_result",
          message: "Geçerli bir medya URL'si bulunamadı",
        },
      };
    }

    const mediaType = selectedMedia.type || detectMediaType(selectedMedia.url);

    // Decode SnapSave render token if present so we download the real file instead of an HTML page
    let finalDownloadUrl = selectedMedia.url;
    if (finalDownloadUrl.includes("render.php?token=")) {
      try {
        const tokenParts = finalDownloadUrl.split("token=")[1]?.split(".");
        if (tokenParts && tokenParts.length > 1) {
          const payload = tokenParts[1];
          const decoded = Buffer.from(payload, "base64").toString("utf8");
          const parsed = JSON.parse(decoded);
          // Prefer audio_url if mediaType is audio, otherwise video_url
          if (mediaType === "audio" && parsed.audio_url) {
            finalDownloadUrl = parsed.audio_url;
          } else if (parsed.video_url) {
            finalDownloadUrl = parsed.video_url;
          }
        }
      } catch (e) {
        console.error("[SNAPSAVE] Failed to decode render token", e);
      }
    }

    const ext = getFileExtension(finalDownloadUrl, mediaType);

    return {
      success: true,
      data: {
        downloadUrl: finalDownloadUrl,
        filename: `${platform}_${Date.now()}${ext}`,
        platform,
        title: result.data.description,
        thumbnail: result.data.preview || selectedMedia.thumbnail,
        mediaType,
      },
    };
  } catch (error) {
    console.error(`[SNAPSAVE] ${platform} error:`, error);
    return {
      success: false,
      error: {
        code: "error.download.failed",
        message: error instanceof Error ? error.message : `${platform} indirme hatası`,
      },
    };
  }
}

// ============================================
// Main Download Functions
// ============================================

/**
 * Main download function
 * Routes to platform-specific downloaders based on URL and request parameters
 */
export async function fetchVideo(request: DownloadRequest): Promise<DownloadResponse> {
  console.log("[DOWNLOADER] Starting download for URL:", request.url);
  console.log("[DOWNLOADER] Request parameters:", {
    quality: request.quality,
    audioFormat: request.audioFormat,
    audioBitrate: request.audioBitrate,
  });

  const platform = detectPlatform(request.url);
  console.log("[DOWNLOADER] Detected platform:", platform);

  switch (platform) {
    case "youtube":
      // If audioFormat is specified, download as audio (MP3)
      if (request.audioFormat) {
        console.log("[DOWNLOADER] YouTube audio download requested");
        return downloadYoutubeAudio(request.url, request.audioFormat, request.audioBitrate);
      }
      // Otherwise download as video (MP4)
      console.log("[DOWNLOADER] YouTube video download requested");
      return downloadYoutubeVideo(request.url, request.quality);

    case "instagram":
      return downloadWithSnapSave(request.url, platform);

    case "tiktok":
      return downloadWithSnapSave(request.url, platform);

    case "twitter":
      return downloadWithSnapSave(request.url, platform);

    case "facebook":
      console.log("[DOWNLOADER] Facebook video download requested");
      const snapResult = await downloadWithSnapSave(request.url, platform);
      if (snapResult.success) {
        return snapResult;
      }
      console.log("[DOWNLOADER] SnapSave failed for Facebook, falling back to yt-dlp...");
      return downloadFromFacebookYtDlp(request.url);

    default:
      return {
        success: false,
        error: {
          code: "error.download.unsupported_platform",
          message:
            "Desteklenmeyen platform. Desteklenenler: YouTube, Instagram, TikTok, Twitter/X, Facebook",
        },
      };
  }
}

/**
 * Download YouTube video (MP4)
 * @param url - YouTube URL or video ID
 * @param quality - Video quality (144, 360, 480, 720, 1080)
 */
export async function fetchYoutubeVideo(
  url: string,
  quality?: VideoQuality
): Promise<DownloadResponse> {
  return downloadYoutubeVideo(url, quality);
}

/**
 * Download YouTube audio (MP3)
 * @param url - YouTube URL or video ID
 * @param bitrate - Audio bitrate (92, 128, 256, 320 kbps)
 */
export async function fetchYoutubeAudio(
  url: string,
  bitrate?: string
): Promise<DownloadResponse> {
  return downloadYoutubeAudio(url, undefined, bitrate);
}

/**
 * Gets video info without downloading
 */
export async function getVideoInfo(
  url: string
): Promise<{ title?: string; thumbnail?: string; platform?: Platform }> {
  const platform = detectPlatform(url);

  if (platform === "youtube") {
    const metadata = await getYoutubeMetadata(url);
    if (metadata) {
      return {
        title: metadata.title,
        thumbnail: metadata.thumbnail,
        platform,
      };
    }
  }

  return { platform: platform || undefined };
}

// Re-export types for convenience
export type { DownloadRequest, DownloadResponse, Platform, MediaType };