'use strict';

/**
 * ChainPay License Routes
 *
 * Business rules enforced server-side:
 *  FREE  — 50 payments/month, BTC+LTC only, no key needed
 *  PRO   — Unlimited, all 14 coins, domain-locked license key
 *
 * Domain locking:
 *  - First activation binds the key to that domain
 *  - Subsequent verifications MUST come from the same domain
 *  - Deactivation clears the domain so it can be re-activated elsewhere
 */

const router = require('express').Router();
const crypto = require('crypto');
const { v4: uuidv4 } = require('uuid');
const { body, validationResult } = require('express-validator');
const { query, queryOne, transaction } = require('../config/db');
const { requireAuth, requireAdmin } = require('../middleware/auth');
const { logAudit } = require('../services/audit');
const { sendEmail } = require('../services/email');

const FREE_MONTHLY_LIMIT = 50;

// ── Helpers ───────────────────────────────────────────────────────
function generateLicenseKey() {
  const s = () => crypto.randomBytes(4).toString('hex');
  return `cp_lic_${s()}-${s()}-${s()}-${s()}`;
}
function hashKey(k) {
  return crypto.createHash('sha256').update(k).digest('hex');
}

// Normalize domain — strip trailing slash, force lowercase
function normalizeDomain(d) {
  if (!d) return '';
  return d.replace(/\/+$/, '').toLowerCase().trim();
}

// ── GET monthly usage for a user ─────────────────────────────────
async function getMonthlyUsage(userId) {
  const monthStart = new Date();
  monthStart.setDate(1);
  monthStart.setHours(0, 0, 0, 0);

  const row = await queryOne(
    `SELECT COUNT(*) as cnt FROM invoices
     WHERE user_id = ? AND created_at >= ? AND status != 'cancelled'`,
    [userId, monthStart.toISOString().slice(0, 19).replace('T', ' ')]
  );
  return row ? parseInt(row.cnt) : 0;
}

// ══════════════════════════════════════════════════════════════════
// POST /licenses/verify  — called by WP plugin on every load/daily
// ══════════════════════════════════════════════════════════════════
router.post('/verify', async (req, res) => {
  const { license_key, domain, plugin_ver, monthly_count } = req.body;

  if (!license_key) {
    return res.status(400).json({ active: false, message: 'License key required.' });
  }

  const normalizedDomain = normalizeDomain(domain);

  try {
    const lic = await queryOne(
      `SELECT l.*, u.email, u.name, u.id as user_id_ref
       FROM licenses l
       LEFT JOIN users u ON u.id = l.user_id
       WHERE l.license_key = ?`,
      [license_key]
    );

    // Key not found
    if (!lic) {
      return res.json({ active: false, message: 'Invalid license key. Purchase at chainpay.store/pricing.' });
    }

    // Revoked
    if (lic.status === 'revoked') {
      return res.json({ active: false, message: 'License has been revoked. Contact support@chainpay.store.' });
    }

    // Expired
    if (lic.expires_at && new Date(lic.expires_at) < new Date()) {
      await query('UPDATE licenses SET status = "expired" WHERE id = ?', [lic.id]);
      return res.json({
        active: false,
        message: 'License expired. Renew at chainpay.store/pricing.',
        expired_at: lic.expires_at,
      });
    }

    // ── DOMAIN LOCKING ─────────────────────────────────────────
    const registeredDomain = normalizeDomain(lic.domain);

    if (registeredDomain && normalizedDomain && registeredDomain !== normalizedDomain) {
      // Key is locked to a different domain — HARD BLOCK
      return res.json({
        active: false,
        code: 'DOMAIN_LOCKED',
        message: `This license is activated on ${registeredDomain}. To transfer, deactivate it there first, then activate here.`,
        registered_domain: registeredDomain,
      });
    }

    // First activation — bind domain
    if (!registeredDomain && normalizedDomain) {
      await query(
        'UPDATE licenses SET domain = ?, status = "active", activated_at = COALESCE(activated_at, NOW()) WHERE id = ?',
        [normalizedDomain, lic.id]
      );
      lic.domain = normalizedDomain;
    }

    // Update last check + plugin version
    await query(
      'UPDATE licenses SET last_check = NOW(), check_count = check_count + 1, plugin_ver = ? WHERE id = ?',
      [plugin_ver || null, lic.id]
    );

    // Get real monthly usage from DB
    const serverMonthlyCount = lic.user_id ? await getMonthlyUsage(lic.user_id) : 0;

    return res.json({
      active:          true,
      plan:            lic.plan,
      expires:         lic.expires_at,
      domain:          lic.domain || normalizedDomain,
      coins_unlocked:  14,
      monthly_limit:   'unlimited',
      monthly_count:   serverMonthlyCount,
      features:        ['all_coins', 'unlimited_payments', 'smart_routing', 'webhooks', 'api', 'underpayment_recovery'],
      message:         'License valid.',
    });

  } catch (err) {
    console.error('[LICENSE] Verify error:', err);
    return res.status(500).json({ active: false, message: 'Verification service error. Try again.' });
  }
});

// ══════════════════════════════════════════════════════════════════
// POST /licenses/deactivate  — clears domain binding
// ══════════════════════════════════════════════════════════════════
router.post('/deactivate', async (req, res) => {
  const { license_key, domain } = req.body;
  if (!license_key) return res.status(400).json({ ok: false, message: 'license_key required.' });

  try {
    const lic = await queryOne('SELECT id, domain FROM licenses WHERE license_key = ?', [license_key]);
    if (!lic) return res.json({ ok: false, message: 'Key not found.' });

    const normalizedDomain = normalizeDomain(domain);
    const licDomain        = normalizeDomain(lic.domain);

    // Only allow deactivation from the registered domain
    if (licDomain && normalizedDomain && licDomain !== normalizedDomain) {
      return res.json({
        ok:      false,
        message: `Can only deactivate from the registered domain (${licDomain}).`,
      });
    }

    // Clear domain binding — key can now be activated on a new domain
    await query('UPDATE licenses SET domain = NULL WHERE id = ?', [lic.id]);

    return res.json({ ok: true, message: 'License deactivated. You can now activate it on another domain.' });
  } catch (err) {
    return res.status(500).json({ ok: false, message: 'Server error.' });
  }
});

// ══════════════════════════════════════════════════════════════════
// GET /licenses  — user's own licenses (or all for admin)
// ══════════════════════════════════════════════════════════════════
router.get('/', requireAuth, async (req, res) => {
  try {
    let rows;
    if (req.user.role === 'admin' || req.user.role === 'superadmin') {
      rows = await query(
        `SELECT l.*, u.email, u.name
         FROM licenses l LEFT JOIN users u ON u.id = l.user_id
         ORDER BY l.created_at DESC LIMIT 200`
      );
    } else {
      rows = await query(
        `SELECT uuid, license_key, plan, status, domain, activated_at, expires_at, check_count, created_at
         FROM licenses WHERE user_id = ? ORDER BY created_at DESC`,
        [req.user.id]
      );
    }
    return res.json({ licenses: rows });
  } catch (err) {
    return res.status(500).json({ error: 'Failed to fetch licenses.' });
  }
});

// ── GET /licenses/:uuid ───────────────────────────────────────────
router.get('/:uuid', requireAuth, async (req, res) => {
  try {
    const isAdmin = req.user.role === 'admin' || req.user.role === 'superadmin';
    const lic = await queryOne(
      'SELECT * FROM licenses WHERE uuid = ? AND (user_id = ? OR ? = true)',
      [req.params.uuid, req.user.id, isAdmin]
    );
    if (!lic) return res.status(404).json({ error: 'License not found.' });

    // Current monthly usage
    const monthlyCount = lic.user_id ? await getMonthlyUsage(lic.user_id) : 0;
    return res.json({ license: { ...lic, monthly_count: monthlyCount, monthly_limit: 'unlimited' } });
  } catch (err) {
    return res.status(500).json({ error: 'Failed.' });
  }
});

// ── POST /licenses  — admin: generate key ────────────────────────
router.post('/', requireAuth, requireAdmin,
  [
    body('plan').isIn(['pro', 'enterprise']),
    body('expires_days').optional().isInt({ min: 1 }),
  ],
  async (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });

    const { plan = 'pro', user_email, expires_days = 365, notes } = req.body;

    try {
      let userId = null;
      if (user_email) {
        const u = await queryOne('SELECT id FROM users WHERE email = ?', [user_email]);
        if (u) {
          userId = u.id;
          await query('UPDATE users SET plan = ? WHERE id = ?', [plan, userId]);
        }
      }

      const rawKey  = generateLicenseKey();
      const keyHash = hashKey(rawKey);
      const uuid    = uuidv4();
      const expires = new Date();
      expires.setDate(expires.getDate() + parseInt(expires_days));

      await query(
        `INSERT INTO licenses (uuid, user_id, license_key, key_hash, plan, status, expires_at, notes)
         VALUES (?, ?, ?, ?, ?, "pending", ?, ?)`,
        [uuid, userId, rawKey, keyHash, plan, expires, notes || null]
      );

      await logAudit(null, req.user.id, 'license.create', 'license', uuid, { plan, user_email });

      // Email key to user
      if (userId && user_email) {
        await sendEmail({
          to:       user_email,
          subject:  '🎉 Your ChainPay Pro License Key',
          template: 'license_created',
          data:     { license_key: rawKey, plan, expires: expires.toDateString() },
        }).catch(console.error);
      }

      return res.status(201).json({
        license: {
          uuid,
          license_key: rawKey,
          plan,
          status: 'pending',
          domain: null,
          expires_at: expires,
        },
        message: 'License generated.' + (user_email ? ' Email sent.' : ' Key shown once — save it.'),
      });

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

// ── DELETE /licenses/:uuid  — admin: revoke ───────────────────────
router.delete('/:uuid', requireAuth, requireAdmin, async (req, res) => {
  try {
    const lic = await queryOne('SELECT id, user_id FROM licenses WHERE uuid = ?', [req.params.uuid]);
    if (!lic) return res.status(404).json({ error: 'Not found.' });

    await query('UPDATE licenses SET status = "revoked", domain = NULL WHERE id = ?', [lic.id]);
    if (lic.user_id) await query('UPDATE users SET plan = "free" WHERE id = ?', [lic.user_id]);

    await logAudit(null, req.user.id, 'license.revoke', 'license', req.params.uuid, {});
    return res.json({ ok: true, message: 'License revoked. User downgraded to free.' });
  } catch (err) {
    return res.status(500).json({ error: 'Failed.' });
  }
});

// ── POST /licenses/:uuid/transfer  — move to new domain ──────────
router.post('/:uuid/transfer', requireAuth, requireAdmin, async (req, res) => {
  const { new_domain } = req.body;
  if (!new_domain) return res.status(400).json({ error: 'new_domain required.' });

  try {
    const lic = await queryOne('SELECT id FROM licenses WHERE uuid = ?', [req.params.uuid]);
    if (!lic) return res.status(404).json({ error: 'Not found.' });

    const normalized = normalizeDomain(new_domain);
    await query('UPDATE licenses SET domain = ? WHERE id = ?', [normalized, lic.id]);
    await logAudit(null, req.user.id, 'license.transfer', 'license', req.params.uuid, { new_domain: normalized });

    return res.json({ ok: true, message: `License transferred to ${normalized}.` });
  } catch (err) {
    return res.status(500).json({ error: 'Transfer failed.' });
  }
});

// ── GET /licenses/check/usage  — client checks own usage ─────────
router.get('/check/usage', requireAuth, async (req, res) => {
  try {
    const monthlyCount = await getMonthlyUsage(req.user.id);
    const isPro        = req.user.plan !== 'free';

    return res.json({
      plan:            req.user.plan,
      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,
      reset_date:      new Date(new Date().getFullYear(), new Date().getMonth() + 1, 1).toISOString().slice(0, 10),
    });
  } catch (err) {
    return res.status(500).json({ error: 'Failed.' });
  }
});

module.exports = router;
module.exports.FREE_MONTHLY_LIMIT = FREE_MONTHLY_LIMIT;
module.exports.getMonthlyUsage = getMonthlyUsage;
