import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

// Carpetas de búsqueda (prioridad en 'cookie' en singular como pidió el usuario)
const PRIMARY_DIR = path.join(__dirname, '..', 'cookie');
const SECONDARY_DIR = path.join(__dirname, '..', 'cookies');
const FALLBACK_FILE = path.join(__dirname, '..', 'full-cookies.json');

// Pool de sesiones de cookies en memoria
let __cookiePool = [];
let __activeCookieIndex = 0;
let __lastDirMtime = 0;

/**
 * Normaliza cualquier estructura JSON a un array de sesiones de cookies.
 * Soporta:
 *  - 1 archivo con 1 cookie: [ { name: '...', value: '...' } ]
 *  - 1 archivo con 1 array de múltiples cookies: [ [ { name: '...' } ], [ { name: '...' } ] ]
 *  - 1 objeto { cookies: [...] } o { pool: [...] }
 */
function parseCookieEntries(rawJson, fileName, filePath) {
  let parsed;
  try {
    parsed = JSON.parse(rawJson);
  } catch (err) {
    console.error(`[CookieManager] Error parseando JSON en ${fileName}:`, err.message);
    return [];
  }

  if (!parsed) return [];

  // Caso 1: Array de múltiples arrays de cookies (varias cookies en un solo archivo)
  if (Array.isArray(parsed) && parsed.length > 0 && Array.isArray(parsed[0])) {
    return parsed.map((session, idx) => ({
      id: `${fileName}#${idx + 1}`,
      fileName,
      filePath,
      indexInFile: idx,
      isMultiFile: true,
      cookies: session,
      failures: 0,
    }));
  }

  // Caso 2: Array simple de cookies (1 sesión por archivo)
  if (Array.isArray(parsed) && parsed.length > 0 && typeof parsed[0] === 'object' && parsed[0] !== null && 'name' in parsed[0]) {
    return [{
      id: fileName,
      fileName,
      filePath,
      indexInFile: 0,
      isMultiFile: false,
      cookies: parsed,
      failures: 0,
    }];
  }

  // Caso 3: Objeto envoltorio { pool: [ ... ] } o { cookies: [ ... ] }
  if (typeof parsed === 'object' && parsed !== null) {
    const list = Array.isArray(parsed.pool) ? parsed.pool : (Array.isArray(parsed.cookies) ? parsed.cookies : null);
    if (list) {
      if (Array.isArray(list[0])) {
        return list.map((session, idx) => ({
          id: `${fileName}#${idx + 1}`,
          fileName,
          filePath,
          indexInFile: idx,
          isMultiFile: true,
          cookies: session,
          failures: 0,
        }));
      } else if (typeof list[0] === 'object' && list[0] !== null && 'name' in list[0]) {
        return [{
          id: fileName,
          fileName,
          filePath,
          indexInFile: 0,
          isMultiFile: false,
          cookies: list,
          failures: 0,
        }];
      }
    }
  }

  return [];
}

/**
 * Escanea las carpetas 'cookie/' y 'cookies/' y recarga el pool completo de cookies.
 */
export function reloadCookiePool(force = false) {
  if (!fs.existsSync(PRIMARY_DIR)) {
    fs.mkdirSync(PRIMARY_DIR, { recursive: true });
  }

  let currentMtime = 0;
  try {
    currentMtime = fs.statSync(PRIMARY_DIR).mtimeMs;
  } catch {}

  // Si ya tenemos cookies en memoria y la carpeta no ha cambiado, evitamos leer disco
  if (!force && __cookiePool.length > 0 && currentMtime === __lastDirMtime) {
    return __cookiePool;
  }

  const newPool = [];
  const scannedDirs = [PRIMARY_DIR];
  if (fs.existsSync(SECONDARY_DIR) && SECONDARY_DIR !== PRIMARY_DIR) {
    scannedDirs.push(SECONDARY_DIR);
  }

  for (const dir of scannedDirs) {
    try {
      const files = fs.readdirSync(dir).filter(f => f.endsWith('.json')).sort();
      for (const file of files) {
        const fullPath = path.join(dir, file);
        const raw = fs.readFileSync(fullPath, 'utf-8');
        const entries = parseCookieEntries(raw, file, fullPath);
        newPool.push(...entries);
      }
    } catch (e) {
      console.error(`[CookieManager] Error escaneando ${dir}:`, e.message);
    }
  }

  __lastDirMtime = currentMtime;

  // Fallback si la carpeta está vacía pero existe full-cookies.json
  if (newPool.length === 0 && fs.existsSync(FALLBACK_FILE)) {
    try {
      const raw = fs.readFileSync(FALLBACK_FILE, 'utf-8');
      const entries = parseCookieEntries(raw, 'full-cookies.json', FALLBACK_FILE);
      newPool.push(...entries);
    } catch (_e) {}
  }

  // Preservar la sesión actual si sigue existiendo
  const previousActiveId = __cookiePool[__activeCookieIndex]?.id;
  __cookiePool = newPool;

  if (__cookiePool.length === 0) {
    __activeCookieIndex = 0;
  } else if (previousActiveId) {
    const foundIdx = __cookiePool.findIndex(c => c.id === previousActiveId);
    __activeCookieIndex = foundIdx >= 0 ? foundIdx : 0;
  } else {
    __activeCookieIndex = 0;
  }

  return __cookiePool;
}

/**
 * Retorna el pool completo de cookies cargadas.
 */
export function getCookiePool() {
  if (__cookiePool.length === 0) {
    reloadCookiePool();
  }
  return __cookiePool;
}

/**
 * Retorna la cookie activa actual lista para usar en requests.
 */
export function getActiveCookie() {
  if (__cookiePool.length === 0) {
    reloadCookiePool();
  }
  if (__cookiePool.length === 0) return null;
  return __cookiePool[__activeCookieIndex];
}

/**
 * Avanza a la siguiente cookie del pool.
 */
export function rotateCookie() {
  if (__cookiePool.length <= 1) return;
  __activeCookieIndex = (__activeCookieIndex + 1) % __cookiePool.length;
}

/**
 * Registra que la cookie actual falló (DataDome o expirada) y rota inmediatamente a la siguiente.
 */
export function markCurrentCookieFailed() {
  if (__cookiePool.length === 0) return null;

  const failedCookie = __cookiePool[__activeCookieIndex];
  failedCookie.failures = (failedCookie.failures || 0) + 1;

  console.warn(`[CookiePool] ⚠️ Cookie [${failedCookie.id}] falló. Rotando a la siguiente...`);
  rotateCookie();

  const nextCookie = getActiveCookie();
  console.log(`[CookiePool] ➡️ Nueva cookie activa: [${nextCookie?.id}]`);
  return nextCookie;
}

/**
 * Registra que la cookie actual respondió con éxito (ok o invalid_id),
 * reseteando sus fallas para conservarla como activa.
 */
export function resetCurrentCookieSuccess() {
  if (__cookiePool.length === 0) return;
  const current = __cookiePool[__activeCookieIndex];
  if (current) {
    current.failures = 0;
  }
}

/**
 * Actualiza el valor de cookies modificadas (ej. nuevo datadome) en memoria y disco.
 */
export function persistActiveCookieUpdate(newCookiesMap) {
  if (__cookiePool.length === 0) return;
  const current = __cookiePool[__activeCookieIndex];
  if (!current || !current.filePath || !fs.existsSync(current.filePath)) return;

  try {
    const updated = current.cookies.map(c => {
      if (newCookiesMap.has(c.name)) {
        return { ...c, value: newCookiesMap.get(c.name) };
      }
      return c;
    });

    const existingNames = new Set(updated.map(c => c.name));
    for (const [name, value] of newCookiesMap.entries()) {
      if (!existingNames.has(name)) {
        updated.push({ name, value, domain: '.pagostore.com', path: '/' });
      }
    }

    current.cookies = updated;

    // Si el archivo contiene múltiples sesiones
    if (current.isMultiFile) {
      const raw = fs.readFileSync(current.filePath, 'utf-8');
      const allSets = JSON.parse(raw);
      if (Array.isArray(allSets) && Array.isArray(allSets[current.indexInFile])) {
        allSets[current.indexInFile] = updated;
        fs.writeFileSync(current.filePath, JSON.stringify(allSets, null, 2));
      }
    } else {
      // Archivo de sesión única
      fs.writeFileSync(current.filePath, JSON.stringify(updated, null, 2));
    }
  } catch (e) {
    console.error(`[CookiePool] Error guardando actualización de cookie ${current.id}:`, e.message);
  }
}

/**
 * Retorna el estado resumido del pool para el panel de administración.
 */
export function getCookiePoolStatus() {
  if (__cookiePool.length === 0) {
    reloadCookiePool();
  }

  return {
    total: __cookiePool.length,
    activeIndex: __activeCookieIndex,
    activeDisplayIndex: __activeCookieIndex + 1,
    activeId: __cookiePool[__activeCookieIndex]?.id || null,
    cookies: __cookiePool.map((c, idx) => {
      let status = 'ready';
      if (c.failures > 0) {
        status = 'failed';
      }
      if (idx === __activeCookieIndex) {
        status = c.failures > 0 ? 'failed' : 'active';
      }
      return {
        index: idx,
        displayIndex: idx + 1,
        id: c.id,
        fileName: c.fileName,
        status, // 'active' (verde) | 'failed' (rojo) | 'ready' (disponible/en espera)
        failures: c.failures || 0,
      };
    }),
  };
}

/**
 * Permite al admin forzar manualmente el índice activo (0-based).
 */
export function setActiveCookieIndex(index) {
  if (__cookiePool.length === 0) reloadCookiePool();
  if (__cookiePool.length === 0) return null;

  const target = Math.max(0, Math.min(__cookiePool.length - 1, Number(index)));
  __activeCookieIndex = target;
  if (__cookiePool[target]) {
    __cookiePool[target].failures = 0; // resetear fallas al activar manualmente
  }
  return getCookiePoolStatus();
}

/**
 * Resetea el contador de fallas de todas las cookies (ej. tras regenerar).
 */
export function resetAllCookieFailures() {
  reloadCookiePool(true);
  for (const c of __cookiePool) {
    c.failures = 0;
  }
  __activeCookieIndex = 0;
  return getCookiePoolStatus();
}
