/**
 * Voucher Cache Warmer Service
 * Melakukan pre-warming cache untuk voucher profiles dan payment channels
 * agar halaman voucher selalu cepat diakses
 */

const { logger } = require('../config/logger');
const { parseMikhmonOnLogin } = require('../utils/mikhmonParser');

// Flag untuk mencegah multiple warming berjalan bersamaan
let isWarming = false;
let warmingInterval = null;

/**
 * Warm up voucher cache
 * Dipanggil secara berkala untuk memastikan cache selalu fresh
 */
async function warmVoucherCache() {
  if (isWarming) {
    logger.debug('[VoucherCacheWarmer] Already warming, skip');
    return;
  }

  isWarming = true;
  const startTime = Date.now();

  try {
    // Import di dalam fungsi untuk menghindari circular dependency
    const mikrotikService = require('./mikrotikService');
    const paymentSvc = require('./paymentService');
    const { getSettingsWithCache } = require('../config/settingsManager');
    const db = require('../config/database');

    logger.info('[VoucherCacheWarmer] Starting cache warming...');

    // Get settings
    const settings = getSettingsWithCache();

    // 1. Warm voucher profiles cache
    const CACHE_KEY = 'voucher_profiles_cache';
    const routers = mikrotikService.getAllRouters().filter(r => r.is_active);
    const routerList = routers.length > 0 ? routers : [{ id: null, name: '' }];

    // Query database dan MikroTik secara parallel
    const [configuredPricesMap, mikrotikResults] = await Promise.all([
      (async () => {
        const map = new Map();
        try {
          const rows = db.prepare(`
            SELECT router_id, profile_name, price, validity
            FROM voucher_batches
            WHERE price > 0
            GROUP BY router_id, profile_name
            HAVING id = MAX(id)
          `).all();
          for (const row of rows) {
            const key = `${row.router_id}_${row.profile_name}`;
            map.set(key, { price: row.price, validity: row.validity });
          }
        } catch (e) {
          logger.error('[VoucherCacheWarmer] Error loading configured prices: ' + e.message);
        }
        return map;
      })(),
      (async () => {
        try {
          // Query semua router secara parallel dengan timeout per router
          const results = await Promise.allSettled(
            routerList.map(r =>
              Promise.race([
                mikrotikService.getHotspotUserProfiles(r.id),
                new Promise((_, reject) =>
                  setTimeout(() => reject(new Error(`Timeout for router ${r.name || r.id}`)), 4000)
                )
              ])
            )
          );
          return results;
        } catch (e) {
          logger.error('[VoucherCacheWarmer] Error querying MikroTik: ' + e.message);
          return [];
        }
      })()
    ]);

    // Process profiles
    const allRows = [];
    if (Array.isArray(mikrotikResults)) {
      for (let i = 0; i < mikrotikResults.length; i++) {
        const result = mikrotikResults[i];
        const router = routerList[i];
        if (result.status !== 'fulfilled' || !Array.isArray(result.value)) {
          logger.warn(`[VoucherCacheWarmer] Router ${router.name || router.id} query failed or returned invalid data`);
          continue;
        }
        for (const p of result.value) {
          allRows.push({
            routerId: router.id ?? null,
            name: p?.name,
            onLogin: p?.onLogin ?? p?.['on-login']
          });
        }
      }
    }

    logger.info(`[VoucherCacheWarmer] Found ${allRows.length} profiles from MikroTik`);

    const bestByName = new Map();
    let skippedCount = 0;
    for (const row of allRows) {
      const name = String(row.name || '').trim();
      if (!name) continue;

      // Parse Mikhmon metadata (gunakan shared parser agar konsisten dengan route handler)
      const onLogin = String(row.onLogin || '').trim();
      const meta = parseMikhmonOnLogin(onLogin);
      let price = Number(meta?.price || 0) || 0;
      let validity = String(meta?.validity || '').trim();
      
      if (price <= 0 || !validity) {
        const key = `${row.routerId}_${name}`;
        const configured = configuredPricesMap.get(key);
        if (configured) {
          price = Number(configured.price || 0) || 0;
          validity = String(configured.validity || '').trim();
        }
      }
      
      if (price <= 0) {
        skippedCount++;
        logger.debug(`[VoucherCacheWarmer] Skipped profile "${name}" - no price (onLogin: ${onLogin || 'empty'})`);
        continue;
      }
      if (!validity) validity = '-';

      const existing = bestByName.get(name);
      if (!existing || Number(price) < Number(existing.price || 0)) {
        bestByName.set(name, { name, validity, price, router_id: row.routerId });
      }
    }
    
    if (skippedCount > 0) {
      logger.warn(`[VoucherCacheWarmer] Skipped ${skippedCount} profiles without price metadata. Add Mikhmon metadata (e.g., $10000^1d) to profile's on-login script or configure price in voucher_batches table.`);
    }

    const profiles = Array.from(bestByName.values()).sort((a, b) => Number(a.price || 0) - Number(b.price || 0));
    
    // Save to cache
    global[CACHE_KEY] = {
      data: profiles,
      timestamp: Date.now()
    };

    logger.info(`[VoucherCacheWarmer] Profiles cached: ${profiles.length} profiles`);

    // 2. Warm payment channels cache
    const gateway = settings.default_gateway || 'tripay';
    const gatewayEnabled = {
      tripay: settings.tripay_enabled && settings.tripay_api_key,
      midtrans: settings.midtrans_enabled && settings.midtrans_server_key,
      xendit: settings.xendit_enabled && settings.xendit_api_key,
      duitku: settings.duitku_enabled && settings.duitku_api_key
    };

    if (gatewayEnabled[gateway]) {
      const PAYMENT_CACHE_KEY = `voucher_payment_channels_cache_${gateway}`;
      let channels = [];

      if (gateway === 'tripay') {
        try {
          channels = await Promise.race([
            paymentSvc.getTripayChannels(),
            new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), 1500))
          ]);
        } catch (e) {
          logger.warn('[VoucherCacheWarmer] Tripay channels fetch failed: ' + e.message);
          channels = [];
        }
      } else {
        const base = [
          { code: 'QRIS', name: 'QRIS', group: 'QRIS', active: true },
          { code: 'BCAVA', name: 'BCA Virtual Account', group: 'Virtual Account', active: true },
          { code: 'BNIVA', name: 'BNI Virtual Account', group: 'Virtual Account', active: true },
          { code: 'BRIVA', name: 'BRI Virtual Account', group: 'Virtual Account', active: true },
          { code: 'PERMATAVA', name: 'Permata Virtual Account', group: 'Virtual Account', active: true },
          { code: 'MANDIRIVA', name: 'Mandiri Virtual Account', group: 'Virtual Account', active: true }
        ];
        if (gateway === 'midtrans') channels = [{ code: 'SNAP', name: 'Semua Metode (Snap)', group: 'E-Wallet', active: true }, ...base];
        else if (gateway === 'xendit') channels = [{ code: 'XENDIT', name: 'Semua Metode', group: 'E-Wallet', active: true }, ...base];
        else if (gateway === 'duitku') channels = [{ code: 'DUITKU', name: 'Semua Metode', group: 'E-Wallet', active: true }, ...base];
        else channels = base;
      }

      global[PAYMENT_CACHE_KEY] = {
        data: channels,
        timestamp: Date.now()
      };

      logger.info(`[VoucherCacheWarmer] Payment channels cached: ${channels.length} channels`);
    }

    const duration = Date.now() - startTime;
    logger.info(`[VoucherCacheWarmer] Cache warming completed in ${duration}ms`);

  } catch (error) {
    logger.error('[VoucherCacheWarmer] Error warming cache:', error.message);
  } finally {
    isWarming = false;
  }
}

/**
 * Start background cache warming
 * Warm cache setiap 8 menit (sebelum cache 10 menit expired)
 */
function startCacheWarming() {
  if (warmingInterval) {
    logger.warn('[VoucherCacheWarmer] Already started');
    return;
  }

  // Warm immediately on start (500ms delay agar app sudah siap)
  setTimeout(() => {
    warmVoucherCache().catch(err => {
      logger.error('[VoucherCacheWarmer] Initial warming failed:', err.message);
    });
  }, 500); // 500ms setelah aplikasi start (lebih cepat siap)

  // Then warm every 8 minutes
  warmingInterval = setInterval(() => {
    warmVoucherCache().catch(err => {
      logger.error('[VoucherCacheWarmer] Periodic warming failed:', err.message);
    });
  }, 3 * 60 * 1000); // 3 menit (agar profile selalu up-to-date)

  logger.info('[VoucherCacheWarmer] Background cache warming started (every 3 minutes)');
}

/**
 * Stop background cache warming
 */
function stopCacheWarming() {
  if (warmingInterval) {
    clearInterval(warmingInterval);
    warmingInterval = null;
    logger.info('[VoucherCacheWarmer] Background cache warming stopped');
  }
}

module.exports = {
  warmVoucherCache,
  startCacheWarming,
  stopCacheWarming
};

// Made with Bob
