/**
 * Cobalt API Client
 * Handles communication with Cobalt API for social media downloads
 */

import {
  CobaltResponse,
  DownloadRequest,
  VideoQuality,
  AudioFormat,
  Platform,
} from "@/types/download";

// Cobalt API instance URL (public instance - v8)
// NOTE: v7 API was shut down on Nov 11th 2024
const COBALT_API_URL =
  process.env.COBALT_API_URL || "https://api.cobalt.tools/api/json";

// Request timeout in milliseconds
const REQUEST_TIMEOUT = 30000;

/**
 * Maps our quality to Cobalt quality format
 */
function mapQuality(quality?: VideoQuality): string {
  const qualityMap: Record<VideoQuality, string> = {
    max: "max",
    "1080": "1080",
    "720": "720",
    "480": "480",
    "360": "360",
  };
  return quality ? qualityMap[quality] : "720";
}

/**
 * Cobalt API request body
 */
interface CobaltRequestBody {
  url: string;
  vCodec?: "h264" | "av1" | "vp9";
  vQuality?: string;
  aFormat?: AudioFormat;
  aBitrate?: "320" | "256" | "128" | "64";
  isAudioOnly?: boolean;
  isAudioMuted?: boolean;
  dubBrowserLang?: boolean;
  filenamePattern?: "classic" | "pretty" | "basic" | "nerdy";
  twitterGif?: boolean;
  tiktokFullAudio?: boolean;
  tiktokH265?: boolean;
  twitterXUrl?: boolean;
}

/**
 * Makes a request to Cobalt API
 */
export async function fetchFromCobalt(
  request: DownloadRequest,
): Promise<CobaltResponse> {
  console.log("[COBALT] Starting fetch for URL:", request.url);
  console.log("[COBALT] Using API URL:", COBALT_API_URL);

  const requestBody: CobaltRequestBody = {
    url: request.url,
    vQuality: mapQuality(request.quality),
    filenamePattern: "pretty",
    aFormat: request.audioFormat || "mp3",
    aBitrate: request.audioBitrate || "128",
    tiktokFullAudio: true,
    twitterXUrl: true,
  };

  console.log("[COBALT] Request body:", JSON.stringify(requestBody, null, 2));

  try {
    console.log("[COBALT] Sending POST request...");
    const response = await fetch(COBALT_API_URL, {
      method: "POST",
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json",
      },
      body: JSON.stringify(requestBody),
      signal: AbortSignal.timeout(REQUEST_TIMEOUT),
    });

    console.log("[COBALT] Response status:", response.status, response.statusText);
    console.log("[COBALT] Response headers:", Object.fromEntries(response.headers.entries()));

    const data = await response.json();
    console.log("[COBALT] Response data:", JSON.stringify(data, null, 2));

    if (!response.ok) {
      console.log("[COBALT] Response not OK, handling error...");
      // Handle Cobalt error response
      if (data.error) {
        console.log("[COBALT] Error from Cobalt:", data.error);
        return {
          error: {
            code: data.error.code || "error.api.fetch.fail",
            message: data.error.message || "Failed to fetch from Cobalt API",
          },
        };
      }

      return {
        error: {
          code: "error.api.fetch.fail",
          message: `API error: ${response.status} ${response.statusText}`,
        },
      };
    }

    console.log("[COBALT] Success! Returning data");
    return data as CobaltResponse;
  } catch (error) {
    console.error("[COBALT] Exception occurred:");
    console.error("[COBALT] Error type:", error?.constructor?.name);
    console.error("[COBALT] Error message:", error instanceof Error ? error.message : String(error));

    if (error instanceof Error) {
      if (error.name === "AbortError" || error.name === "TimeoutError") {
        return {
          error: {
            code: "error.api.fetch.timeout",
            message: "Request timed out. Please try again.",
          },
        };
      }

      return {
        error: {
          code: "error.api.fetch.fail",
          message: error.message,
        },
      };
    }

    return {
      error: {
        code: "error.api.fetch.fail",
        message: "An unexpected error occurred",
      },
    };
  }
}

/**
 * Gets video info from Cobalt API
 * Note: Cobalt doesn't have a separate info endpoint, so we use the main endpoint
 * and extract info from the response
 */
export async function getVideoInfo(
  url: string,
): Promise<{
  success: boolean;
  data?: {
    title?: string;
    thumbnail?: string;
    platform?: Platform;
  };
  error?: { code: string; message: string };
}> {
  try {
    // Make a request to get video info
    const response = await fetchFromCobalt({ url });

    if ("error" in response) {
      return {
        success: false,
        error: {
          code: response.error.code,
          message: response.error.message || "Unknown error",
        },
      };
    }

    // Extract available info from Cobalt response
    if (response.status === "redirect" || response.status === "stream") {
      return {
        success: true,
        data: {
          // Cobalt doesn't provide title/thumbnail in basic response
          // These would need additional API calls or scraping
        },
      };
    }

    if (response.status === "picker" && response.picker) {
      return {
        success: true,
        data: {
          // Picker means multiple options (e.g., Instagram carousel)
          thumbnail: response.picker[0]?.thumb,
        },
      };
    }

    return {
      success: true,
    };
  } catch (error) {
    return {
      success: false,
      error: {
        code: "error.api.info.fail",
        message:
          error instanceof Error ? error.message : "Failed to get video info",
      },
    };
  }
}

/**
 * Parses Cobalt error codes to user-friendly messages
 */
export function parseCobaltError(
  errorCode: string,
  locale: string = "en",
): { title: string; description: string } {
  const messages: Record<
    string,
    Record<string, { title: string; description: string }>
  > = {
    "error.api.link.invalid": {
      en: { title: "Invalid URL", description: "The provided URL is not valid." },
      tr: { title: "Geçersiz URL", description: "Sağlanan URL geçerli değil." },
    },
    "error.api.fetch.fail": {
      en: {
        title: "Fetch Failed",
        description: "Could not fetch the content. Please try again.",
      },
      tr: {
        title: "İndirme Başarısız",
        description: "İçerik alınamadı. Lütfen tekrar deneyin.",
      },
    },
    "error.api.content.unavailable": {
      en: {
        title: "Content Unavailable",
        description: "This content is not available or has been removed.",
      },
      tr: {
        title: "İçerik Mevcut Değil",
        description: "Bu içerik mevcut değil veya kaldırılmış.",
      },
    },
    "error.api.rate_exceeded": {
      en: {
        title: "Rate Limited",
        description: "Too many requests. Please wait a moment and try again.",
      },
      tr: {
        title: "Sınır Aşıldı",
        description: "Çok fazla istek. Lütfen bekleyip tekrar deneyin.",
      },
    },
    "error.api.fetch.rate": {
      en: {
        title: "Service Busy",
        description: "The service is currently busy. Please try again later.",
      },
      tr: {
        title: "Servis Meşgul",
        description: "Servis şu anda meşgul. Lütfen daha sonra tekrar deneyin.",
      },
    },
    "error.api.content.video_region": {
      en: {
        title: "Region Restricted",
        description: "This video is not available in your region.",
      },
      tr: {
        title: "Bölge Kısıtlaması",
        description: "Bu video bölgenizde mevcut değil.",
      },
    },
    "error.api.content.post.private": {
      en: {
        title: "Private Content",
        description: "This content is private and cannot be downloaded.",
      },
      tr: {
        title: "Özel İçerik",
        description: "Bu içerik özel ve indirilemez.",
      },
    },
    "error.api.fetch.short": {
      en: {
        title: "Link Expired",
        description: "This link has expired. Please get a fresh link.",
      },
      tr: {
        title: "Bağlantı Süresi Doldu",
        description: "Bu bağlantının süresi doldu. Lütfen yeni bir bağlantı alın.",
      },
    },
    "error.api.fetch.critical": {
      en: {
        title: "Critical Error",
        description: "A critical error occurred. Please contact support if this persists.",
      },
      tr: {
        title: "Kritik Hata",
        description: "Kritik bir hata oluştu. Bu devam ederse destekle iletişime geçin.",
      },
    },
    "error.api.fetch.timeout": {
      en: {
        title: "Request Timeout",
        description: "The request took too long. Please try again.",
      },
      tr: {
        title: "Zaman Aşımı",
        description: "İstek çok uzun sürdü. Lütfen tekrar deneyin.",
      },
    },
  };

  const localeMessages = messages[errorCode] || messages["error.api.fetch.fail"];
  return localeMessages[locale] || localeMessages["en"];
}

/**
 * Gets direct download URL from Cobalt response
 */
export function getDownloadUrl(response: CobaltResponse): string | null {
  console.log("[COBALT] Extracting download URL from response...");
  
  if ("error" in response) {
    console.log("[COBALT] Response has error, no download URL");
    return null;
  }

  if (response.status === "redirect" && response.url) {
    console.log("[COBALT] Found redirect URL:", response.url);
    return response.url;
  }

  if (response.status === "stream" && response.url) {
    console.log("[COBALT] Found stream URL:", response.url);
    return response.url;
  }

  if (response.status === "picker" && response.picker?.length) {
    console.log("[COBALT] Found picker URL:", response.picker[0].url);
    return response.picker[0].url;
  }

  console.log("[COBALT] No download URL found in response");
  return null;
}
