import { Router } from 'express';
import path from 'path';
import { fileURLToPath } from 'url';
import fs from 'fs';
import { refreshSingleUser, updateMissingNicknames } from '../services/admin.js';
import { readDB, readDBOnce, withDB } from '../db.js';
import { readSettings, writeSettings } from '../services/settings.js';
import { isSolverReady } from '../services/datadome.js';
import { hashPin } from '../services/creatorAuth.js';
import { TWOCAPTCHA_API_KEY, DATADOME_PROXY_CONFIGURED } from '../config.js';
import { REFRESH_PROGRESS_FILE } from '../config.js';
import { fetchPlayerInfo } from '../services/garena.js';
import { 
  getCookiePoolStatus, 
  setActiveCookieIndex, 
  resetAllCookieFailures 
} from '../services/cookieManager.js';
import { createBackup } from '../services/backupManager.js';
import {
  clearAdminSession,
  isAdminAuthenticated,
  isAdminConfigured,
  requireAdmin,
  setAdminSession,
  verifyAdminPassword,
} from '../middleware/adminAuth.js';

const router = Router();
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const COOKIE_DIR = path.join(__dirname, '..', 'cookie');
const COOKIE_FILE = path.join(COOKIE_DIR, 'cookie-1.json');

router.get('/api/admin/session', (req, res) => {
  res.json({ authenticated: isAdminAuthenticated(req), configured: isAdminConfigured() });
});

router.post('/api/admin/login', (req, res) => {
  if (!isAdminConfigured()) {
    return res.status(503).json({ error: 'admin_not_configured', message: 'Configura la contraseña de admin en config-private.php.' });
  }
  const password = String(req.body?.password || '');
  if (!verifyAdminPassword(password)) {
    return res.status(401).json({ error: 'invalid_admin_password', message: 'Contraseña incorrecta.' });
  }
  setAdminSession(res);
  res.json({ success: true });
});

router.post('/api/admin/logout', (req, res) => {
  clearAdminSession(res);
  res.json({ success: true });
});

router.use('/api/admin', requireAdmin);

// ---------- Withdrawals management ----------

router.get('/api/admin/withdrawals', async (req, res) => {
  try {
    const db = await readDBOnce();
    const withdrawals = [...(db.withdrawals || [])]
      .sort((a, b) => String(b.createdAt).localeCompare(String(a.createdAt)))
      .map((w) => ({
        ...w,
        creatorName: db.creators?.[w.code]?.name || '',
      }));
    res.json({ success: true, withdrawals });
  } catch (_e) {
    res.status(500).json({ error: 'db_error', message: 'No se pudieron leer los retiros.' });
  }
});

router.patch('/api/admin/withdrawals/:id', async (req, res) => {
  const action = String(req.body?.action || '').toLowerCase();
  if (!['approve', 'reject'].includes(action)) {
    return res.status(400).json({ error: 'invalid_action', message: 'Acción inválida (approve|reject).' });
  }

  let result;
  try {
    result = await withDB((db) => {
      db.withdrawals ??= [];
      db.creators ??= {};
      const w = db.withdrawals.find((x) => x.id === req.params.id);
      if (!w) return { status: 404, body: { error: 'not_found', message: 'Retiro no encontrado.' } };
      if (w.status !== 'pending') {
        return { status: 409, body: { error: 'already_processed', message: `Este retiro ya fue procesado (${w.status}).` } };
      }

      if (action === 'approve') {
        // El saldo ya fue reservado al solicitar; solo marcamos pagado.
        w.status = 'paid';
        w.processedAt = new Date().toISOString();
        return { status: 200, body: { success: true, withdrawal: w } };
      }

      // reject → reembolsar el monto exacto reservado
      w.status = 'rejected';
      w.processedAt = new Date().toISOString();
      const creator = db.creators[w.code];
      let refunded = false;
      if (creator) {
        creator.balance = Math.round((Number(creator.balance || 0) + Number(w.amount || 0) + Number.EPSILON) * 100) / 100;
        refunded = true;
      }
      return { status: 200, body: { success: true, withdrawal: w, refunded } };
    });
  } catch (_e) {
    return res.status(500).json({ error: 'db_error', message: 'No se pudo procesar el retiro.' });
  }
  res.status(result.status).json(result.body);
});

// ---------- Runtime settings (DataDome flags) ----------

router.get('/api/admin/settings', (req, res) => {
  const settings = readSettings();
  res.json({
    success: true,
    settings,
    twocaptchaConfigured: isSolverReady() && Boolean(TWOCAPTCHA_API_KEY),
    proxyConfigured: DATADOME_PROXY_CONFIGURED,
  });
});

router.put('/api/admin/settings', (req, res) => {
  const patch = {};
  if (typeof req.body?.datadomeEnabled === 'boolean') patch.datadomeEnabled = req.body.datadomeEnabled;
  if (typeof req.body?.datadomeAuto === 'boolean') patch.datadomeAuto = req.body.datadomeAuto;
  if (typeof req.body?.levelPackagesEnabled === 'boolean') patch.levelPackagesEnabled = req.body.levelPackagesEnabled;
  if (Object.keys(patch).length === 0) {
    return res.status(400).json({ error: 'nothing_to_update', message: 'No hay cambios válidos.' });
  }
  try {
    const settings = writeSettings(patch);
    res.json({ success: true, settings });
  } catch (_e) {
    res.status(500).json({ error: 'write_error', message: 'No se pudo guardar settings.json.' });
  }
});

// ---------- Packages / Pricing editor ----------

const CONFIG_JSON_FILE = path.join(__dirname, '..', 'config.json');

router.get('/api/admin/packages', (_req, res) => {
  try {
    const cfg = JSON.parse(fs.readFileSync(CONFIG_JSON_FILE, 'utf-8'));
    res.json({ success: true, pricing: cfg.pricing || {}, packages: cfg.packages || [], levelPackages: cfg.levelPackages || [] });
  } catch {
    res.status(500).json({ error: 'read_error', message: 'No se pudo leer config.json.' });
  }
});

router.put('/api/admin/packages', (req, res) => {
  try {
    const cfg = JSON.parse(fs.readFileSync(CONFIG_JSON_FILE, 'utf-8'));
    if (!cfg.pricing) cfg.pricing = {};
    const { pricing, packages, levelPackages } = req.body;

    if (pricing && typeof pricing === 'object') {
      const dp = Number(pricing.discountPercent);
      const pp = Number(pricing.profitPercent);
      if (Number.isFinite(dp) && dp >= 0 && dp < 100) cfg.pricing.discountPercent = dp;
      if (Number.isFinite(pp) && pp >= 0) cfg.pricing.profitPercent = pp;
    }

    if (Array.isArray(packages)) {
      for (let i = 0; i < packages.length; i++) {
        const p = packages[i];
        if (!p.id || typeof p.id !== 'string')
          return res.status(400).json({ error: 'validation', message: `Paquete #${i + 1}: ID inválido.` });
        
        const size = Number(p.size);
        if (!Number.isFinite(size) || size <= 0)
          return res.status(400).json({ error: 'validation', message: `${p.id}: diamantes debe ser > 0.` });
          
        const newPkg = { id: p.id, size, aliases: p.aliases, composition: p.composition };
        
        // Normal
        if (p.normal) {
          const cost = Number(p.normal.cost);
          const profit = Number(p.normal.profit);
          if (!p.composition && (!Number.isFinite(cost) || cost <= 0))
            return res.status(400).json({ error: 'validation', message: `${p.id}: Costo Normal debe ser > 0.` });
          if (!Number.isFinite(profit) || profit < 0)
            return res.status(400).json({ error: 'validation', message: `${p.id}: Ganancia Normal inválida.` });
          newPkg.normal = { cost, profit };
        } else if (p.usd) { // Legacy fallback
          newPkg.usd = Number(p.usd);
          newPkg.profitPercent = Number(p.profitPercent) || 0;
        }

        // Promo
        if (p.promo) {
          const cost = Number(p.promo.cost);
          const profit = Number(p.promo.profit);
          if (!Number.isFinite(cost) || cost <= 0)
            return res.status(400).json({ error: 'validation', message: `${p.id}: Costo Promo debe ser > 0.` });
          if (!Number.isFinite(profit) || profit < 0)
            return res.status(400).json({ error: 'validation', message: `${p.id}: Ganancia Promo inválida.` });
          newPkg.promo = { cost, profit };
        }
        
        packages[i] = newPkg;
      }
      cfg.packages = packages;
    }

    if (Array.isArray(levelPackages)) {
      for (let i = 0; i < levelPackages.length; i++) {
        const lp = levelPackages[i];
        const diamonds = Number(lp.diamonds);
        const usd = Number(lp.usd);
        if (!lp.id || typeof lp.id !== 'string')
          return res.status(400).json({ error: 'validation', message: `Nivel #${i + 1}: ID inválido.` });
        if (!Number.isFinite(diamonds) || diamonds <= 0)
          return res.status(400).json({ error: 'validation', message: `${lp.id}: diamantes debe ser > 0.` });
        if (!Number.isFinite(usd) || usd <= 0)
          return res.status(400).json({ error: 'validation', message: `${lp.id}: USD debe ser > 0.` });
        const level = Number(lp.level);
        levelPackages[i] = {
          ...lp,
          diamonds, usd,
          ...(Number.isFinite(level) && { level }),
        };
      }
      cfg.levelPackages = levelPackages;
    }

    const tmp = CONFIG_JSON_FILE + '.tmp';
    fs.writeFileSync(tmp, JSON.stringify(cfg, null, 2) + '\n', 'utf-8');
    fs.renameSync(tmp, CONFIG_JSON_FILE);
    res.json({ success: true });
  } catch {
    res.status(500).json({ error: 'write_error', message: 'No se pudo guardar config.json.' });
  }
});

// ---------- Creators management ----------

const CODE_RE = /^[A-Z0-9]{3,20}$/;

// Commission percentages: 0-100 with one decimal, fallback to defaults.
function sanitizeCommission(value, fallback) {
  if (value === undefined || value === null || value === '') return fallback;
  const n = Number(value);
  if (!Number.isFinite(n)) return fallback;
  return Math.min(100, Math.max(0, Math.round(n * 10) / 10));
}

// PIN de creador: 4-8 dígitos. Devuelve string válido o null (autogenerar).
function sanitizePin(value) {
  const pin = String(value ?? '').trim();
  return /^\d{4,8}$/.test(pin) ? pin : null;
}

const generatePin = () => String(Math.floor(100000 + Math.random() * 900000));

// List creators as an array (stable order by code)
router.get('/api/admin/creators', async (req, res) => {
  try {
    const db = await readDBOnce();
    const creators = Object.entries(db.creators || {}).map(([code, c]) => ({
      code,
      name: c.name || '',
      status: c.status || 'inactive',
      balance: Number(c.balance || 0),
      totalReferrals: Number(c.totalReferrals || 0),
      clicks: Number(c.clicks || 0),
      commissionBonusPercent: Number(c.commissionBonusPercent ?? 7),
      commissionNormalPercent: Number(c.commissionNormalPercent ?? 5),
      hasPin: Boolean(c.pinHash),
    }));
    creators.sort((a, b) => a.code.localeCompare(b.code));
    res.json({ success: true, creators });
  } catch (_e) {
    res.status(500).json({ error: 'db_error', message: 'No se pudo leer creators.json.' });
  }
});

// Create a creator
router.post('/api/admin/creators', async (req, res) => {
  const code = String(req.body?.code || '').trim().toUpperCase();
  const name = String(req.body?.name || '').trim();
  if (!CODE_RE.test(code)) {
    return res.status(400).json({ error: 'invalid_code', message: 'El código debe tener 3-20 caracteres (letras/números).' });
  }
  if (!name || name.length > 60) {
    return res.status(400).json({ error: 'invalid_name', message: 'El nombre es obligatorio (máx. 60 caracteres).' });
  }

  let result;
  let generatedPin = null;
  try {
    result = await withDB((db) => {
      db.creators ??= {};
      if (db.creators[code]) {
        return { status: 409, body: { error: 'code_exists', message: `El código '${code}' ya existe.` } };
      }
      const pin = sanitizePin(req.body?.pin) || (generatedPin = generatePin());
      db.creators[code] = {
        name,
        status: 'active',
        balance: 0,
        totalReferrals: 0,
        clicks: 0,
        commissionBonusPercent: sanitizeCommission(req.body?.commissionBonusPercent, 7),
        commissionNormalPercent: sanitizeCommission(req.body?.commissionNormalPercent, 5),
        commissionComboPercent: sanitizeCommission(req.body?.commissionComboPercent, 3),
        pinHash: hashPin(pin),
      };
      return { status: 200, body: { success: true, code } };
    });
  } catch (_e) {
    return res.status(500).json({ error: 'db_error', message: 'No se pudo crear el creador.' });
  }
  if (result.status === 200 && generatedPin) {
    result.body.pin = generatedPin; // se muestra UNA sola vez al admin
  }
  res.status(result.status).json(result.body);
});

// Update a creator (rename / activate / deactivate)
router.patch('/api/admin/creators/:code', async (req, res) => {
  const code = String(req.params.code || '').trim().toUpperCase();
  const name = req.body?.name === undefined ? undefined : String(req.body.name).trim();
  const status = req.body?.status === undefined ? undefined : String(req.body.status).toLowerCase();

  if (name !== undefined && (!name || name.length > 60)) {
    return res.status(400).json({ error: 'invalid_name', message: 'Nombre inválido.' });
  }
  if (status !== undefined && !['active', 'inactive'].includes(status)) {
    return res.status(400).json({ error: 'invalid_status', message: 'Estado inválido (active|inactive).' });
  }
  const patch = {};
  if (name !== undefined) patch.name = name;
  if (status !== undefined) patch.status = status;
  if (req.body?.commissionBonusPercent !== undefined) patch.commissionBonusPercent = sanitizeCommission(req.body.commissionBonusPercent, 7);
  if (req.body?.commissionNormalPercent !== undefined) patch.commissionNormalPercent = sanitizeCommission(req.body.commissionNormalPercent, 5);
  if (req.body?.commissionComboPercent !== undefined) patch.commissionComboPercent = sanitizeCommission(req.body.commissionComboPercent, 3);
  const newPin = req.body?.pin === undefined ? null : sanitizePin(req.body.pin);
  if (req.body?.pin !== undefined && !newPin) {
    return res.status(400).json({ error: 'invalid_pin', message: 'El PIN debe tener 4-8 dígitos.' });
  }
  if (Object.keys(patch).length === 0 && !newPin) {
    return res.status(400).json({ error: 'nothing_to_update', message: 'No hay cambios válidos.' });
  }

  let result;
  try {
    result = await withDB((db) => {
      db.creators ??= {};
      const creator = db.creators[code];
      if (!creator) return { status: 404, body: { error: 'not_found', message: `El código '${code}' no existe.` } };
      if (patch.name !== undefined) creator.name = patch.name;
      if (patch.status !== undefined) creator.status = patch.status;
      if (patch.commissionBonusPercent !== undefined) creator.commissionBonusPercent = patch.commissionBonusPercent;
      if (patch.commissionNormalPercent !== undefined) creator.commissionNormalPercent = patch.commissionNormalPercent;
      if (patch.commissionComboPercent !== undefined) creator.commissionComboPercent = patch.commissionComboPercent;
      if (newPin) creator.pinHash = hashPin(newPin);
      return { status: 200, body: { success: true, code, creator } };
    });
  } catch (_e) {
    return res.status(500).json({ error: 'db_error', message: 'No se pudo actualizar el creador.' });
  }
  res.status(result.status).json(result.body);
});

// Delete a creator (blocked while they have pending balance)
router.delete('/api/admin/creators/:code', async (req, res) => {
  const code = String(req.params.code || '').trim().toUpperCase();

  let result;
  try {
    result = await withDB((db) => {
      db.creators ??= {};
      const creator = db.creators[code];
      if (!creator) return { status: 404, body: { error: 'not_found', message: `El código '${code}' no existe.` } };
      if (Number(creator.balance || 0) > 0) {
        return { status: 409, body: { error: 'has_balance', message: `'${code}' tiene saldo pendiente ($${Number(creator.balance).toFixed(2)}). Ponlo en inactive o paga el saldo antes de eliminar.` } };
      }
      const hasPendingWithdrawals = (db.withdrawals || []).some((w) => w.code === code && w.status === 'pending');
      if (hasPendingWithdrawals) {
        return { status: 409, body: { error: 'pending_withdrawals', message: `'${code}' tiene solicitudes de retiro pendientes. Apruébalas o recházalas antes de eliminar.` } };
      }
      delete db.creators[code];
      return { status: 200, body: { success: true, code } };
    });
  } catch (_e) {
    return res.status(500).json({ error: 'db_error', message: 'No se pudo eliminar el creador.' });
  }
  res.status(result.status).json(result.body);
});

// GET current cookie file as JSON
router.get('/api/admin/full-cookies', (req, res) => {
  try {
    const raw = fs.readFileSync(COOKIE_FILE, 'utf-8');
    const data = JSON.parse(raw);
    res.json({ content: data });
  } catch (e) {
    console.error('Read cookie error:', e);
    res.status(500).json({ error: 'read_cookie_error', message: e.message });
  }
});

// POST updated cookie content (expects { content: [...] })
router.post('/api/admin/full-cookies', (req, res) => {
  const { content } = req.body;
  if (!content) {
    return res.status(400).json({ error: 'missing_content', message: 'No cookie data provided.' });
  }
  try {
    const json = JSON.stringify(content, null, 2);
    fs.writeFileSync(COOKIE_FILE, json, 'utf-8');
    res.json({ success: true });
  } catch (e) {
    console.error('Write cookie error:', e);
    res.status(500).json({ error: 'write_cookie_error', message: e.message });
  }
});

// POST trigger to refresh nicknames for users missing them
router.post('/api/admin/update-missing-nicknames', async (req, res) => {
  try {
    const { updated } = await updateMissingNicknames();
    res.json({ success: true, updated });
  } catch (e) {
    console.error('Update nicknames error:', e);
    res.status(500).json({ error: 'update_error', message: e.message });
  }
});

router.get('/api/admin/check-cookie/:id', async (req, res) => {
  try {
    const result = await fetchPlayerInfo(req.params.id);
    if (result.status === 'ok') {
      return res.json({ ok: true });
    }
    return res.json({ ok: false, error: result.status });
  } catch (e) {
    console.error('Check cookie error:', e);
    res.status(500).json({ ok: false, error: 'error' });
  }
});

// GET estado detallado del pool de cookies
router.get('/api/admin/cookie-pool', (req, res) => {
  try {
    const status = getCookiePoolStatus();
    res.json(status);
  } catch (e) {
    res.status(500).json({ error: 'pool_error', message: e.message });
  }
});

// POST cambiar el índice activo manualmente
router.post('/api/admin/cookie-pool/set-index', (req, res) => {
  try {
    const { index } = req.body;
    const result = setActiveCookieIndex(index);
    if (!result) return res.status(400).json({ error: 'invalid_index', message: 'Índice fuera de rango o pool vacío.' });
    res.json({ success: true, ...result });
  } catch (e) {
    res.status(500).json({ error: 'set_index_error', message: e.message });
  }
});

// POST resetear fallas y reiniciar pool desde el índice 1
router.post('/api/admin/cookie-pool/reset-failures', (req, res) => {
  try {
    const result = resetAllCookieFailures();
    res.json({ success: true, ...result });
  } catch (e) {
    res.status(500).json({ error: 'reset_error', message: e.message });
  }
});

// POST disparar respaldo manual de la base de datos
router.post('/api/admin/backup', (req, res) => {
  try {
    const result = createBackup();
    res.json(result);
  } catch (e) {
    res.status(500).json({ error: 'backup_error', message: e.message });
  }
});

// GET lista de todos los IDs de usuarios registrados (para refresco masivo)
router.get('/api/admin/all-users', (req, res) => {
  const db = readDB();
  const ids = Object.keys(db.users || {});
  res.json({ ids, total: ids.length });
});

// POST refrescar UN solo usuario desde Garena (actualiza nickname, paquetes y descuentos)
router.post('/api/admin/refresh-user/:id', async (req, res) => {
  try {
    const result = await refreshSingleUser(req.params.id);
    res.json(result);
  } catch (e) {
    console.error('Refresh user error:', e);
    res.status(500).json({ status: 'error', updated: false, error: e.message });
  }
});

// GET progreso del refresco masivo (indice guardado en refresh-progress.json)
router.get('/api/admin/refresh-progress', (req, res) => {
  try {
    const raw = fs.readFileSync(REFRESH_PROGRESS_FILE, 'utf-8');
    res.json(JSON.parse(raw));
  } catch {
    res.json({ index: 0, total: null });
  }
});

// PUT actualizar/resetear progreso del refresco masivo
router.put('/api/admin/refresh-progress', (req, res) => {
  const { index, total } = req.body;
  const data = {
    index: typeof index === 'number' ? index : 0,
    total: typeof total === 'number' ? total : null,
  };
  fs.writeFileSync(REFRESH_PROGRESS_FILE, JSON.stringify(data, null, 2));
  res.json(data);
});

export default router;
