/**
 * ETL Daily Sync — MySQL RDS → SQLite Analytics
 * Runs daily at 1 AM via node-cron, computes aggregates for previous day
 */
const cron = require('node-cron');
const pool = require('../db-rds');
const analyticsDb = require('../db-analytics');
const { runDataQuality } = require('./data-quality');

/**
 * Sync a single day's metrics from MySQL to SQLite
 */
async function syncDay(dateStr) {
  const conn = await pool.getConnection();
  try {
    console.log(`[ETL] Syncing day: ${dateStr}`);

    // BRL→USD metrics
    const [brlUsd] = await conn.execute(`
      SELECT
        COUNT(*) as transactions,
        ROUND(COALESCE(SUM(amount_usd), 0), 2) as volume_usd,
        ROUND(COALESCE(SUM(amount_brl), 0), 2) as volume_brl,
        ROUND(COALESCE(SUM((exchange_rate - ptax) / exchange_rate * amount_usd), 0), 2) as revenue,
        ROUND(COALESCE(AVG((exchange_rate - ptax) / exchange_rate * 100), 0), 4) as avg_spread,
        ROUND(COALESCE(AVG(amount_usd), 0), 2) as avg_ticket,
        COUNT(DISTINCT id_conta) as unique_clients
      FROM br_transaction_to_usa
      WHERE DATE(created_at) = ?
    `, [dateStr]);

    // USD→BRL metrics
    const [usdBrl] = await conn.execute(`
      SELECT
        COUNT(*) as transactions,
        ROUND(COALESCE(SUM(valor), 0), 2) as volume_usd,
        ROUND(COALESCE(SUM(valor_sol), 0), 2) as volume_brl,
        ROUND(COALESCE(SUM((ptax - cotacao) / ptax * valor), 0), 2) as revenue,
        ROUND(COALESCE(AVG(CASE WHEN cotacao > 0 THEN (ptax - cotacao) / ptax * 100 ELSE 0 END), 0), 4) as avg_spread,
        ROUND(COALESCE(AVG(valor), 0), 2) as avg_ticket,
        COUNT(DISTINCT id_conta) as unique_clients
      FROM pagamento_br
      WHERE DATE(created_at) = ?
        AND cotacao IS NOT NULL AND cotacao > 0
        AND (pgto IS NULL OR pgto != 'balance')
    `, [dateStr]);

    // USD→USD metrics
    const [usdUsd] = await conn.execute(`
      SELECT
        COUNT(*) as transactions,
        ROUND(COALESCE(SUM(valor), 0), 2) as volume_usd,
        0 as volume_brl,
        0 as revenue,
        0 as avg_spread,
        ROUND(COALESCE(AVG(valor), 0), 2) as avg_ticket,
        COUNT(DISTINCT id_conta) as unique_clients
      FROM pagamento_br
      WHERE DATE(created_at) = ?
        AND (cotacao IS NULL OR cotacao = 0 OR pgto = 'balance')
    `, [dateStr]);

    // Upsert into SQLite
    const upsert = analyticsDb.prepare(`
      INSERT INTO daily_metrics (date, product, transactions, volume_usd, volume_brl, revenue, avg_spread, avg_ticket, unique_clients)
      VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
      ON CONFLICT(date, product) DO UPDATE SET
        transactions=excluded.transactions, volume_usd=excluded.volume_usd, volume_brl=excluded.volume_brl,
        revenue=excluded.revenue, avg_spread=excluded.avg_spread, avg_ticket=excluded.avg_ticket,
        unique_clients=excluded.unique_clients
    `);

    const insertMetrics = analyticsDb.transaction((rows) => {
      rows.forEach(r => upsert.run(r.date, r.product, r.transactions, r.volume_usd, r.volume_brl, r.revenue, r.avg_spread, r.avg_ticket, r.unique_clients));
    });

    const b = brlUsd[0] || {};
    const u = usdBrl[0] || {};
    const uu = usdUsd[0] || {};

    insertMetrics([
      { date: dateStr, product: 'BRL→USD', transactions: Number(b.transactions) || 0, volume_usd: Number(b.volume_usd) || 0, volume_brl: Number(b.volume_brl) || 0, revenue: Number(b.revenue) || 0, avg_spread: Number(b.avg_spread) || 0, avg_ticket: Number(b.avg_ticket) || 0, unique_clients: Number(b.unique_clients) || 0 },
      { date: dateStr, product: 'USD→BRL', transactions: Number(u.transactions) || 0, volume_usd: Number(u.volume_usd) || 0, volume_brl: Number(u.volume_brl) || 0, revenue: Number(u.revenue) || 0, avg_spread: Number(u.avg_spread) || 0, avg_ticket: Number(u.avg_ticket) || 0, unique_clients: Number(u.unique_clients) || 0 },
      { date: dateStr, product: 'USD→USD', transactions: Number(uu.transactions) || 0, volume_usd: Number(uu.volume_usd) || 0, volume_brl: 0, revenue: 0, avg_spread: 0, avg_ticket: Number(uu.avg_ticket) || 0, unique_clients: Number(uu.unique_clients) || 0 }
    ]);

    // Monthly revenue aggregation
    const month = dateStr.slice(0, 7);
    const [monthlyRevBrl] = await conn.execute(`
      SELECT id_conta,
        ROUND(SUM((exchange_rate - ptax) / exchange_rate * amount_usd), 2) as revenue,
        ROUND(SUM(amount_usd), 2) as volume_usd,
        COUNT(*) as tx_count
      FROM br_transaction_to_usa
      WHERE DATE_FORMAT(created_at, '%Y-%m') = ? AND DATE(created_at) <= ?
      GROUP BY id_conta
    `, [month, dateStr]);

    const [monthlyRevUsd] = await conn.execute(`
      SELECT id_conta,
        ROUND(SUM((ptax - cotacao) / ptax * valor), 2) as revenue,
        ROUND(SUM(valor), 2) as volume_usd,
        COUNT(*) as tx_count
      FROM pagamento_br
      WHERE DATE_FORMAT(created_at, '%Y-%m') = ? AND DATE(created_at) <= ?
        AND cotacao IS NOT NULL AND cotacao > 0
        AND (pgto IS NULL OR pgto != 'balance')
      GROUP BY id_conta
    `, [month, dateStr]);

    const monthlyUpsert = analyticsDb.prepare(`
      INSERT INTO monthly_revenue (month, id_conta, revenue, volume_usd, tx_count)
      VALUES (?, ?, ?, ?, ?)
      ON CONFLICT(month, id_conta) DO UPDATE SET
        revenue=excluded.revenue, volume_usd=excluded.volume_usd, tx_count=excluded.tx_count
    `);

    const clientMap = {};
    [...monthlyRevBrl, ...monthlyRevUsd].forEach(r => {
      const id = r.id_conta;
      if (!clientMap[id]) clientMap[id] = { revenue: 0, volume_usd: 0, tx_count: 0 };
      clientMap[id].revenue += Number(r.revenue) || 0;
      clientMap[id].volume_usd += Number(r.volume_usd) || 0;
      clientMap[id].tx_count += Number(r.tx_count) || 0;
    });

    const insertMonthly = analyticsDb.transaction((map) => {
      Object.entries(map).forEach(([id, d]) => {
        monthlyUpsert.run(month, parseInt(id), Math.round(d.revenue * 100) / 100, Math.round(d.volume_usd * 100) / 100, d.tx_count);
      });
    });
    insertMonthly(clientMap);

    console.log(`[ETL] Day ${dateStr} synced: BRL→USD=${b.transactions || 0}tx, USD→BRL=${u.transactions || 0}tx, USD→USD=${uu.transactions || 0}tx, ${Object.keys(clientMap).length} client revenue records`);
    return true;
  } finally {
    conn.release();
  }
}

/**
 * Backfill: sync multiple days
 */
async function backfill(daysBack = 90) {
  console.log(`[ETL] Backfilling ${daysBack} days...`);
  const now = new Date();
  for (let i = daysBack; i >= 1; i--) {
    const d = new Date(now.getTime() - i * 86400000);
    const dateStr = d.toISOString().slice(0, 10);
    try {
      await syncDay(dateStr);
    } catch (err) {
      console.error(`[ETL] Backfill error for ${dateStr}:`, err.message);
    }
  }
  console.log(`[ETL] Backfill complete`);
}

/**
 * Start daily ETL sync job
 */
function startETL() {
  // Run at 1:00 AM every day
  cron.schedule('0 1 * * *', async () => {
    try {
      // Sync yesterday
      const yesterday = new Date(Date.now() - 86400000).toISOString().slice(0, 10);
      await syncDay(yesterday);
      // Run data quality checks
      runDataQuality(yesterday);
    } catch (err) {
      console.error('[ETL] Daily sync error:', err.message);
    }
  });

  console.log('[ETL] Daily sync scheduled at 1:00 AM');

  // Check if analytics DB is empty; if so, backfill
  const count = analyticsDb.prepare('SELECT COUNT(*) as c FROM daily_metrics').get();
  if (!count || count.c === 0) {
    console.log('[ETL] Analytics DB empty, starting backfill...');
    // Run backfill in background
    backfill(90).catch(err => console.error('[ETL] Backfill error:', err.message));
  }
}

module.exports = { startETL, syncDay, backfill };
