/**
 * routes/billing.js
 * Stripe checkout + customer portal. Webhook is in routes/webhook.js.
 *
 * Checkout accepts:
 *   { plan: 'standard'|'pro'|'agency',
 *     interval: 'month'|'year',         (default 'month')
 *     quantity: 1..50,                 (per-seat plans only; default min)
 *     promo?: 'CODE'                   (optional — coupon code in metadata)
 *
 * If the user has an active subscription and requests a different
 * plan, Stripe handles the upgrade/downgrade via the customer portal.
 * For a clean plan change with prorations, we use
 * `subscription_data.proration_behavior: 'create_prorations'`.
 */

'use strict';

const express = require('express');
const { requireLogin } = require('../middleware/auth');
const User    = require('../models/user');
const Audit   = require('../models/auditLog');
const stripe  = require('../config/stripe');
const { listPlans, getStripePriceId, getPlan, validateQuantity, PLANS } = require('../config/plans');

const router = express.Router();

router.get('/plans', (req, res) => res.json({ plans: listPlans() }));

router.post('/checkout', requireLogin, async (req, res) => {
  if (!stripe) return res.status(500).json({ error: 'STRIPE_NOT_CONFIGURED' });
  const { plan, interval = 'month', quantity, promo } = req.body || {};
  const planDef = PLANS[plan];
  if (!planDef) {
    return res.status(400).json({ error: 'INVALID_PLAN',
      message: `Unknown plan "${plan}".` });
  }
  // Credit packs have no interval/quantity — they're one-shot payments.
  const isCreditPack = planDef.kind === 'credit_pack';
  const effectiveInterval = isCreditPack ? 'one_time' : interval;
  const priceId = getStripePriceId(plan, effectiveInterval);
  if (!priceId) {
    return res.status(400).json({ error: 'INVALID_PLAN_OR_INTERVAL',
      message: `Plan "${plan}" is not available for ${effectiveInterval === 'year' ? 'annual' : effectiveInterval === 'one_time' ? 'one-time' : 'monthly'} billing.` });
  }
  // Quantity: per-seat plans honor the request, others are forced to 1.
  let qty = 1;
  if (planDef.per_seat) {
    qty = validateQuantity(plan, quantity ?? planDef.min_seats);
    if (qty === null) {
      return res.status(400).json({
        error: 'INVALID_QUANTITY',
        message: `Quantity must be between ${planDef.min_seats} and ${planDef.max_seats} for the ${planDef.name} plan.`,
        min: planDef.min_seats, max: planDef.max_seats,
      });
    }
  }

  let customerId = req.user.stripe_customer_id;
  if (!customerId) {
    const customer = await stripe.customers.create({
      email: req.user.email, name: req.user.name,
      metadata: { user_id: String(req.user.id) },
    });
    customerId = customer.id;
    User.setStripeCustomerId(req.user.id, customerId);
  }

  // Build the checkout session. Two flows:
  //   - subscription plans → mode: 'subscription'
  //   - credit packs        → mode: 'payment' (single charge, no sub)
  // Both share: automatic_tax, tax_id_collection, allow_promotion_codes.
  const sessionParams = {
    customer: customerId,
    line_items: [{ price: priceId, quantity: qty }],
    success_url: `${process.env.APP_URL}/billing?status=success`,
    cancel_url:  `${process.env.APP_URL}/billing?status=cancel`,
    allow_promotion_codes: true,
    automatic_tax: { enabled: true },
    tax_id_collection: { enabled: true },
    metadata: {
      user_id:  String(req.user.id),
      plan,
      interval: effectiveInterval,
      quantity: String(qty),
      kind:     isCreditPack ? 'credit_pack' : 'subscription',
    },
  };
  if (isCreditPack) {
    sessionParams.mode = 'payment';
    sessionParams.payment_intent_data = {
      metadata: {
        user_id: String(req.user.id),
        plan,
        kind:    'credit_pack',
      },
      // Apply the coupon if the user supplied one in the form.
      ...(promo ? { discounts: [{ coupon: promo }] } : {}),
    };
  } else {
    sessionParams.mode = 'subscription';
    sessionParams.subscription_data = {
      metadata: {
        user_id:  String(req.user.id),
        plan,
        interval: effectiveInterval,
        quantity: String(qty),
        promo:    promo || '',
      },
      ...(promo ? { discounts: [{ coupon: promo }] } : {}),
    };
  }
  const session = await stripe.checkout.sessions.create(sessionParams);
  Audit.log(req.user, 'billing.checkout', `user:${req.user.id}`,
    { plan, interval: effectiveInterval, quantity: qty, kind: isCreditPack ? 'credit_pack' : 'subscription',
      session_id: session.id, promo: promo || null });
  res.json({ url: session.url });
});

router.post('/portal', requireLogin, async (req, res) => {
  if (!stripe) return res.status(500).json({ error: 'STRIPE_NOT_CONFIGURED' });
  if (!req.user.stripe_customer_id) {
    return res.status(400).json({ error: 'NO_STRIPE_CUSTOMER' });
  }
  const portal = await stripe.billingPortal.sessions.create({
    customer: req.user.stripe_customer_id,
    return_url: `${process.env.APP_URL}/billing`,
  });
  res.json({ url: portal.url });
});

router.get('/me', requireLogin, (req, res) => {
  res.json({
    user: req.user,
    plan: getPlan(req.user.plan, req.user.plan_override),
    payment_failed: !!req.user.payment_failed,
    billing_interval: req.user.billing_interval || null,
    seats: req.user.seats || 1,
    extra_scans: req.user.extra_scans || 0,
    extra_takedowns: req.user.extra_takedowns || 0,
  });
});

module.exports = router;
