// backend/src/routes/stripe.js
import { Router } from 'express';
import Stripe from 'stripe';
import { query } from '../utils/db.js';
import { requireAuth } from '../middleware/auth.js';
import { sendEmail } from '../services/email.js';
import { logger } from '../utils/logger.js';

const router = Router();
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

const PLAN_PRICE_MAP = {
  starter: process.env.STRIPE_STARTER_PRICE_ID,
  pro: process.env.STRIPE_PRO_PRICE_ID,
  agency: process.env.STRIPE_AGENCY_PRICE_ID,
};

// POST /api/stripe/checkout  — create checkout session
router.post('/checkout', requireAuth, async (req, res) => {
  try {
    const { planId } = req.body;
    const priceId = PLAN_PRICE_MAP[planId];
    if (!priceId) return res.status(400).json({ error: 'Invalid plan' });

    const { rows } = await query('SELECT stripe_customer_id, email, full_name FROM users WHERE id = $1', [req.user.id]);
    const user = rows[0];

    // Create Stripe customer if it doesn't exist yet (race condition safety)
    let customerId = user.stripe_customer_id;
    if (!customerId) {
      const customer = await stripe.customers.create({
        email: user.email,
        name: user.full_name,
        metadata: { userId: req.user.id }
      });
      customerId = customer.id;
      await query('UPDATE users SET stripe_customer_id = $1 WHERE id = $2', [customerId, req.user.id]);
    }

    const session = await stripe.checkout.sessions.create({
      customer: customerId,
      payment_method_types: ['card'],
      mode: 'subscription',
      line_items: [{ price: priceId, quantity: 1 }],
      subscription_data: {
        trial_period_days: 14,
        metadata: { userId: req.user.id, planId }
      },
      // Card required to start trial (matches "14 days free, card required" decision)
      payment_method_collection: 'always',
      success_url: `${process.env.APP_URL}/dashboard?payment=success`,
      cancel_url: `${process.env.APP_URL}/dashboard/billing?payment=canceled`,
      metadata: { userId: req.user.id, planId },
      allow_promotion_codes: true,
    });

    res.json({ url: session.url });
  } catch (err) {
    logger.error('Stripe checkout error', err);
    res.status(500).json({ error: 'Failed to create checkout session' });
  }
});

// POST /api/stripe/portal  — customer billing portal
router.post('/portal', requireAuth, async (req, res) => {
  try {
    const { rows } = await query('SELECT stripe_customer_id FROM users WHERE id = $1', [req.user.id]);
    if (!rows[0]?.stripe_customer_id) return res.status(400).json({ error: 'No billing account' });

    const session = await stripe.billingPortal.sessions.create({
      customer: rows[0].stripe_customer_id,
      return_url: `${process.env.APP_URL}/dashboard/billing`,
    });

    res.json({ url: session.url });
  } catch (err) {
    res.status(500).json({ error: 'Failed to create portal session' });
  }
});

// POST /api/stripe/webhook  — raw body required (configured in main app)
router.post('/webhook', async (req, res) => {
  const sig = req.headers['stripe-signature'];
  let event;

  try {
    event = stripe.webhooks.constructEvent(req.rawBody, sig, process.env.STRIPE_WEBHOOK_SECRET);
  } catch (err) {
    logger.warn('Webhook signature verification failed', err.message);
    return res.status(400).send(`Webhook Error: ${err.message}`);
  }

  try {
    switch (event.type) {
      case 'checkout.session.completed': {
        const session = event.data.object;
        const { userId, planId } = session.metadata;
        const sub = await stripe.subscriptions.retrieve(session.subscription);

        await query(
          `UPDATE users SET
            status = 'active', plan_id = $1,
            stripe_subscription_id = $2, stripe_subscription_status = $3,
            current_period_end = $4
           WHERE id = $5`,
          [planId, sub.id, sub.status, new Date(sub.current_period_end * 1000), userId]
        );

        const { rows } = await query('SELECT email, full_name, locale FROM users WHERE id = $1', [userId]);
        if (rows[0]) {
          await sendEmail({
            to: rows[0].email,
            subject: 'Welcome to Content Machine!',
            template: 'welcome-paid',
            data: { name: rows[0].full_name, planId, locale: rows[0].locale }
          });
        }
        break;
      }

      case 'invoice.payment_succeeded': {
        const invoice = event.data.object;
        if (invoice.subscription) {
          const sub = await stripe.subscriptions.retrieve(invoice.subscription);
          await query(
            `UPDATE users SET status = 'active', stripe_subscription_status = $1, current_period_end = $2
             WHERE stripe_subscription_id = $3`,
            [sub.status, new Date(sub.current_period_end * 1000), invoice.subscription]
          );
        }
        break;
      }

      case 'invoice.payment_failed': {
        const invoice = event.data.object;
        await query(
          `UPDATE users SET status = 'past_due' WHERE stripe_subscription_id = $1`,
          [invoice.subscription]
        );
        const { rows } = await query(
          'SELECT email, full_name, locale FROM users WHERE stripe_subscription_id = $1',
          [invoice.subscription]
        );
        if (rows[0]) {
          await sendEmail({ to: rows[0].email, subject: 'Payment failed', template: 'payment-failed', data: { name: rows[0].full_name, locale: rows[0].locale } });
        }
        break;
      }

      case 'customer.subscription.deleted': {
        const sub = event.data.object;
        await query(
          `UPDATE users SET status = 'canceled', stripe_subscription_status = 'canceled' WHERE stripe_subscription_id = $1`,
          [sub.id]
        );
        break;
      }

      case 'customer.subscription.updated': {
        const sub = event.data.object;
        // Map Stripe subscription status to our internal status
        let internalStatus = null;
        if (sub.status === 'active') internalStatus = 'active';
        else if (sub.status === 'trialing') internalStatus = 'trial';
        else if (sub.status === 'past_due' || sub.status === 'unpaid') internalStatus = 'past_due';
        else if (sub.status === 'canceled') internalStatus = 'canceled';

        // Handle plan changes
        const newPriceId = sub.items.data[0]?.price.id;
        const planId = Object.entries(PLAN_PRICE_MAP).find(([, priceId]) => priceId === newPriceId)?.[0];

        await query(
          `UPDATE users SET
            plan_id = COALESCE($1, plan_id),
            status = COALESCE($2, status),
            stripe_subscription_status = $3,
            current_period_end = $4
           WHERE stripe_subscription_id = $5`,
          [planId || null, internalStatus, sub.status, new Date(sub.current_period_end * 1000), sub.id]
        );
        break;
      }
    }

    res.json({ received: true });
  } catch (err) {
    logger.error('Webhook processing error', err);
    res.status(500).json({ error: 'Webhook processing failed' });
  }
});

// GET /api/stripe/plans  — public endpoint
router.get('/plans', async (req, res) => {
  const { rows } = await query('SELECT * FROM plans WHERE active = true ORDER BY price_usd ASC');
  res.json(rows);
});

export default router;
