'use strict';

const router = require('express').Router();
const { v4: uuidv4 } = require('uuid');
const { body, validationResult } = require('express-validator');
const { query, queryOne } = require('../config/db');
const { requireAuth } = require('../middleware/auth');
const { getRate, fiatToCrypto } = require('../services/prices');
const { deriveAddress } = require('../services/wallet');
const { deliverWebhook } = require('../services/webhook');
const { sendEmail } = require('../services/email');
const COINS = require('../config/coins');

const { FREE_MONTHLY_LIMIT, getMonthlyUsage } = require('./licenses');

// Free plan: BTC + LTC only
const FREE_COINS = ['BTC', 'LTC'];

// ── POST /invoices ────────────────────────────────────────────────
router.post('/',
  requireAuth,
  [
    body('order_id').notEmpty(),
    body('coin').notEmpty().isIn(Object.keys(COINS)),
    body('amount').isFloat({ min: 0.01 }),
    body('currency').optional().isLength({ min: 3, max: 5 }),
    body('timeout_min').optional().isInt({ min: 5, max: 120 }),
  ],
  async (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });

    const {
      order_id,
      coin,
      amount,
      currency    = 'USD',
      timeout_min = 15,
      metadata,
      store_id,
    } = req.body;

    const isPro     = req.user.plan !== 'free';
    const coinData  = COINS[coin];

    // ── 1. Coin access ────────────────────────────────────────────
    if (!isPro && !FREE_COINS.includes(coin)) {
      return res.status(402).json({
        error:       `${coinData.name} requires a Pro license.`,
        code:        'LICENSE_REQUIRED',
        free_coins:  FREE_COINS,
        upgrade_url: 'https://chainpay.store/pricing',
      });
    }

    // ── 2. Monthly payment limit (FREE plan only) ─────────────────
    if (!isPro) {
      const monthlyCount = await getMonthlyUsage(req.user.id);
      if (monthlyCount >= FREE_MONTHLY_LIMIT) {
        return res.status(402).json({
          error:             `Free plan limit of ${FREE_MONTHLY_LIMIT} payments/month reached.`,
          code:              'FREE_LIMIT_REACHED',
          monthly_count:     monthlyCount,
          monthly_limit:     FREE_MONTHLY_LIMIT,
          monthly_remaining: 0,
          upgrade_url:       'https://chainpay.store/pricing',
          reset_date:        new Date(new Date().getFullYear(), new Date().getMonth() + 1, 1).toISOString().slice(0, 10),
        });
      }
    }

    try {
      // ── 3. Exchange rate ──────────────────────────────────────────
      const rate = await getRate(coin, currency);
      if (!rate || rate <= 0) {
        return res.status(503).json({ error: `Could not fetch ${coin}/${currency} rate. Try again.` });
      }

      const cryptoAmount = fiatToCrypto(amount, rate, coinData.decimals);
      const feePct       = isPro ? 0.0025 : 0.01;  // 0.25% Pro, 1.0% Free
      const feeFiat      = parseFloat(amount) * feePct;

      // ── 4. Derive address ─────────────────────────────────────────
      const address = await deriveAddress(req.user.id, coin, store_id || null);
      if (!address) {
        return res.status(400).json({
          error: `No xPub configured for ${coin}. Add one in ChainPay → Wallets.`,
          code:  'NO_XPUB',
        });
      }

      const uuid      = uuidv4();
      const expiresAt = new Date(Date.now() + parseInt(timeout_min) * 60 * 1000);
      const uri       = `${coinData.uri_scheme}:${address}?amount=${cryptoAmount}&label=${encodeURIComponent(process.env.PLATFORM_NAME || 'ChainPay')}`;

      // Resolve store
      let resolvedStoreId = store_id || null;
      if (!resolvedStoreId) {
        const defaultStore = await queryOne('SELECT id FROM stores WHERE user_id = ? LIMIT 1', [req.user.id]);
        if (defaultStore) resolvedStoreId = defaultStore.id;
      }

      await query(
        `INSERT INTO invoices
           (uuid, user_id, store_id, external_order_id, coin, network,
            address, amount_crypto, amount_fiat, fiat_currency,
            exchange_rate, fee_pct, fee_fiat, status, metadata, expires_at)
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "pending", ?, ?)`,
        [
          uuid, req.user.id, resolvedStoreId, String(order_id),
          coin, coinData.network, address,
          cryptoAmount, amount, currency,
          rate, feePct, feeFiat,
          metadata ? JSON.stringify(metadata) : null,
          expiresAt,
        ]
      );

      // Current monthly count after this invoice
      const newMonthlyCount = await getMonthlyUsage(req.user.id);

      return res.status(201).json({
        invoice_id:      uuid,
        order_id:        String(order_id),
        coin,
        network:         coinData.network,
        address,
        amount_crypto:   cryptoAmount,
        amount_fiat:     parseFloat(amount),
        fiat_currency:   currency,
        exchange_rate:   rate,
        fee_pct:         feePct,
        uri,
        status:          'pending',
        expires_at:      expiresAt.toISOString(),
        rec_fee:         coinData.rec_fee,
        // Usage info returned so plugin can sync
        monthly_count:   newMonthlyCount,
        monthly_limit:   isPro ? 'unlimited' : FREE_MONTHLY_LIMIT,
        monthly_remaining: isPro ? 'unlimited' : Math.max(0, FREE_MONTHLY_LIMIT - newMonthlyCount),
        coin_data: {
          name:    coinData.name,
          symbol:  coinData.symbol,
          icon:    coinData.icon,
          color:   coinData.color,
          network: coinData.network,
        },
      });

    } catch (err) {
      console.error('[INVOICE] Create error:', err);
      return res.status(500).json({ error: 'Failed to create invoice. Try again.' });
    }
  }
);

// ── GET /invoices ─────────────────────────────────────────────────
router.get('/', requireAuth, async (req, res) => {
  const { status, coin, limit = 50, offset = 0, order_id } = req.query;
  try {
    let sql    = 'SELECT * FROM invoices WHERE user_id = ?';
    const params = [req.user.id];
    if (status)   { sql += ' AND status = ?';              params.push(status); }
    if (coin)     { sql += ' AND coin = ?';                params.push(coin); }
    if (order_id) { sql += ' AND external_order_id = ?';  params.push(order_id); }
    sql += ' ORDER BY created_at DESC LIMIT ? OFFSET ?';
    params.push(parseInt(limit), parseInt(offset));
    const rows = await query(sql, params);
    return res.json({ invoices: rows, limit: parseInt(limit), offset: parseInt(offset) });
  } catch (err) {
    return res.status(500).json({ error: 'Failed.' });
  }
});

// ── GET /invoices/:uuid ───────────────────────────────────────────
router.get('/:uuid', requireAuth, async (req, res) => {
  try {
    const isAdmin = ['admin','superadmin'].includes(req.user.role);
    const inv = await queryOne(
      isAdmin
        ? 'SELECT * FROM invoices WHERE uuid = ?'
        : 'SELECT * FROM invoices WHERE uuid = ? AND user_id = ?',
      isAdmin ? [req.params.uuid] : [req.params.uuid, req.user.id]
    );
    if (!inv) return res.status(404).json({ error: 'Invoice not found.' });
    const coinData = COINS[inv.coin] || {};
    const uri = inv.address ? `${coinData.uri_scheme || 'bitcoin'}:${inv.address}?amount=${inv.amount_crypto}` : null;
    return res.json({ invoice: { ...inv, uri, coin_data: coinData } });
  } catch (err) {
    return res.status(500).json({ error: 'Failed.' });
  }
});

// ── GET /invoices/by-order/:order_id ─────────────────────────────
router.get('/by-order/:order_id', requireAuth, async (req, res) => {
  try {
    const inv = await queryOne(
      'SELECT * FROM invoices WHERE external_order_id = ? AND user_id = ? ORDER BY created_at DESC LIMIT 1',
      [req.params.order_id, req.user.id]
    );
    if (!inv) return res.status(404).json({ error: 'No invoice found.' });
    const coinData = COINS[inv.coin] || {};
    const uri = `${coinData.uri_scheme || 'bitcoin'}:${inv.address}?amount=${inv.amount_crypto}`;
    return res.json({ invoice: { ...inv, uri, coin_data: coinData } });
  } catch (err) {
    return res.status(500).json({ error: 'Failed.' });
  }
});

// ── GET /invoices/:uuid/status  — lightweight poll ────────────────
router.get('/:uuid/status', async (req, res) => {
  try {
    const inv = await queryOne(
      'SELECT uuid, status, confirmations, tx_hash, expires_at, external_order_id, user_id FROM invoices WHERE uuid = ?',
      [req.params.uuid]
    );
    if (!inv) return res.status(404).json({ error: 'Not found.' });

    let redirect_url = null;
    if (inv.status === 'confirmed' && inv.external_order_id) {
      const store = await queryOne('SELECT url FROM stores WHERE user_id = ?', [inv.user_id]);
      if (store) redirect_url = `${store.url}/?order=${inv.external_order_id}&key=received`;
    }

    return res.json({
      status:        inv.status,
      confirmations: inv.confirmations,
      tx_hash:       inv.tx_hash,
      expires_at:    inv.expires_at,
      redirect_url,
    });
  } catch (err) {
    return res.status(500).json({ error: 'Status check failed.' });
  }
});

// ── POST /invoices/:uuid/mark-paid ────────────────────────────────
router.post('/:uuid/mark-paid', requireAuth, async (req, res) => {
  const { tx_hash, confirmations = 0 } = req.body;
  if (!tx_hash) return res.status(400).json({ error: 'tx_hash required.' });

  try {
    const inv = await queryOne('SELECT * FROM invoices WHERE uuid = ?', [req.params.uuid]);
    if (!inv) return res.status(404).json({ error: 'Invoice not found.' });

    const coinData    = COINS[inv.coin] || {};
    const required    = coinData.confirms || 1;
    const newStatus   = confirmations >= required ? 'confirmed' : 'detected';
    const confirmedAt = newStatus === 'confirmed' ? new Date() : null;
    const detectedAt  = inv.detected_at || new Date();

    await query(
      `UPDATE invoices SET status = ?, tx_hash = ?, confirmations = ?,
       detected_at = COALESCE(detected_at, ?), confirmed_at = ?
       WHERE uuid = ?`,
      [newStatus, tx_hash, confirmations, detectedAt, confirmedAt, req.params.uuid]
    );

    // Fire webhooks
    await deliverWebhook(inv.user_id, {
      event:      newStatus === 'confirmed' ? 'payment.confirmed' : 'payment.detected',
      invoice_id: inv.uuid,
      tx_hash,
      confirmations,
      coin:       inv.coin,
      amount:     inv.amount_crypto,
      order_id:   inv.external_order_id,
    }).catch(console.error);

    if (newStatus === 'confirmed') {
      const user = await queryOne('SELECT email, name FROM users WHERE id = ?', [inv.user_id]);
      if (user) {
        await sendEmail({
          to:       user.email,
          subject:  `Payment confirmed — ${inv.amount_crypto} ${inv.coin}`,
          template: 'payment_confirmed_admin',
          data:     { invoice_id: inv.uuid, amount: inv.amount_crypto, coin: inv.coin, tx_hash },
        }).catch(console.error);
      }
    }

    return res.json({ ok: true, status: newStatus });
  } catch (err) {
    console.error('[INVOICE] Mark-paid error:', err);
    return res.status(500).json({ error: 'Failed.' });
  }
});

// ── GET /invoices/stats/summary ───────────────────────────────────
router.get('/stats/summary', requireAuth, async (req, res) => {
  try {
    const monthStart = new Date();
    monthStart.setDate(1); monthStart.setHours(0,0,0,0);
    const ms = monthStart.toISOString().slice(0,19).replace('T',' ');

    const stats = await queryOne(
      `SELECT
        COUNT(*) as total,
        SUM(status='confirmed') as confirmed,
        SUM(status IN ('pending','detected')) as pending,
        SUM(status='expired') as expired,
        COALESCE(SUM(CASE WHEN status='confirmed' THEN amount_fiat END),0) as revenue,
        COUNT(CASE WHEN created_at >= ? THEN 1 END) as this_month
       FROM invoices WHERE user_id = ?`,
      [ms, req.user.id]
    );

    const monthlyCount  = await getMonthlyUsage(req.user.id);
    const isPro         = req.user.plan !== 'free';

    return res.json({
      stats: {
        ...stats,
        monthly_count:     monthlyCount,
        monthly_limit:     isPro ? 'unlimited' : FREE_MONTHLY_LIMIT,
        monthly_remaining: isPro ? 'unlimited' : Math.max(0, FREE_MONTHLY_LIMIT - monthlyCount),
        over_limit:        !isPro && monthlyCount >= FREE_MONTHLY_LIMIT,
      }
    });
  } catch (err) {
    return res.status(500).json({ error: 'Failed.' });
  }
});

module.exports = router;
