/**
 * CurseForge API client — search packs, list versions, download mod files.
 * Task #101 — Modpack Server Installer
 *
 * CurseForge API v1: https://docs.curseforge.com/
 * Requires API key from https://console.curseforge.com
 *
 * Class IDs: 4471 = Modpacks, 6 = Mods
 * Game ID: 432 = Minecraft
 */

const axios = require('axios');

const BASE = 'https://api.curseforge.com/v1';
const API_KEY = process.env.CURSEFORGE_API_KEY || '';
const GAME_ID = 432;
const CLASS_MODPACK = 4471;

function headers() {
  return { 'x-api-key': API_KEY, 'Accept': 'application/json' };
}

/**
 * Search modpacks by query string.
 * Returns { data: [{ id, name, summary, logo, downloadCount, ... }], pagination }
 */
async function searchPacks(query, options = {}) {
  const params = {
    gameId: GAME_ID,
    classId: CLASS_MODPACK,
    searchFilter: query,
    sortField: 2,      // Popularity
    sortOrder: 'desc',
    pageSize: options.pageSize || 20,
    index: options.offset || 0
  };
  if (options.gameVersion) params.gameVersion = options.gameVersion;
  if (options.modLoaderType) params.modLoaderType = options.modLoaderType; // 1=Forge, 4=Fabric, 6=NeoForge

  const resp = await axios.get(`${BASE}/mods/search`, { headers: headers(), params, timeout: 15000 });
  const packs = (resp.data.data || []).map(p => ({
    id: p.id,
    name: p.name,
    summary: p.summary,
    thumbnail: p.logo?.thumbnailUrl || null,
    downloadCount: p.downloadCount,
    modLoader: detectLoader(p.latestFilesIndexes),
    mcVersions: [...new Set((p.latestFilesIndexes || []).map(f => f.gameVersion))].sort().reverse(),
    provider: 'curseforge'
  }));
  return { packs, total: resp.data.pagination?.totalCount || packs.length };
}

/**
 * Get pack details by modpack ID.
 */
async function getPackDetails(modId) {
  const resp = await axios.get(`${BASE}/mods/${modId}`, { headers: headers(), timeout: 10000 });
  const p = resp.data.data;
  return {
    id: p.id,
    name: p.name,
    summary: p.summary,
    description: p.description || p.summary,
    thumbnail: p.logo?.thumbnailUrl || null,
    screenshots: (p.screenshots || []).map(s => s.url),
    downloadCount: p.downloadCount,
    categories: (p.categories || []).map(c => c.name),
    provider: 'curseforge'
  };
}

/**
 * List available versions (files) for a modpack.
 */
async function listVersions(modId) {
  const resp = await axios.get(`${BASE}/mods/${modId}/files`, {
    headers: headers(), params: { pageSize: 50 }, timeout: 10000
  });
  return (resp.data.data || []).map(f => ({
    fileId: f.id,
    displayName: f.displayName,
    fileName: f.fileName,
    gameVersions: f.gameVersions || [],
    modLoader: f.gameVersions?.find(v => /forge|fabric|neoforge/i.test(v)) || null,
    downloadUrl: f.downloadUrl,
    serverPackFileId: f.serverPackFileId || null,
    fileDate: f.fileDate,
    fileLength: f.fileLength
  }));
}

/**
 * Get the download URL for a specific file. Prefer serverPackFileId if available.
 */
async function getDownloadUrl(modId, fileId) {
  const resp = await axios.get(`${BASE}/mods/${modId}/files/${fileId}/download-url`, {
    headers: headers(), timeout: 10000
  });
  return resp.data.data; // direct URL string
}

/**
 * Get mod files for a specific modpack version (the manifest mod list).
 * Returns the manifest from the modpack file.
 */
async function getModManifest(modId, fileId) {
  // CurseForge modpacks use a manifest.json inside the zip.
  // For server installs, use the serverPackFileId which includes only server-side mods.
  // The caller should download the server pack zip and extract.
  return { modId, fileId, note: 'Download server pack zip and parse manifest.json' };
}

function detectLoader(filesIndexes) {
  if (!filesIndexes || filesIndexes.length === 0) return 'unknown';
  const loaders = filesIndexes.map(f => f.modLoader).filter(Boolean);
  if (loaders.includes(6)) return 'NeoForge';
  if (loaders.includes(1)) return 'Forge';
  if (loaders.includes(4)) return 'Fabric';
  return 'unknown';
}

module.exports = { searchPacks, getPackDetails, listVersions, getDownloadUrl, getModManifest };
