// Stripe webhook. Mounted at /api/billing/webhook with a RAW body
// (express.raw) BEFORE express.json() in server.js, so the signature verifies.
// Keeps the subscriptions table in sync; the subscription middleware reads it.
import { Router } from 'express';
import Stripe from 'stripe';
import { ulid } from 'ulid';
import { config } from '../config.js';
import { queryOne, execute } from '../db/client.js';

const router = Router();
const stripe = config.stripe.secretKey ? new Stripe(config.stripe.secretKey) : null;
const now = () => Math.floor(Date.now() / 1000);

// Upsert one subscription row, matched by stripe_subscription_id, then
// stripe_customer_id, then user_id. COALESCE keeps known ids when an event omits them.
async function upsertSub({ userId, customerId, subscriptionId, status, periodEnd }) {
  let row = null;
  if (subscriptionId) row = await queryOne(`SELECT id FROM subscriptions WHERE stripe_subscription_id = ?`, [subscriptionId]);
  if (!row && customerId) row = await queryOne(`SELECT id FROM subscriptions WHERE stripe_customer_id = ?`, [customerId]);
  if (!row && userId) row = await queryOne(`SELECT id FROM subscriptions WHERE user_id = ?`, [userId]);
  if (row) {
    await execute(
      `UPDATE subscriptions SET
         user_id = COALESCE(?, user_id),
         stripe_customer_id = COALESCE(?, stripe_customer_id),
         stripe_subscription_id = COALESCE(?, stripe_subscription_id),
         status = ?,
         current_period_end = COALESCE(?, current_period_end),
         updated_at = ?
       WHERE id = ?`,
      [userId || null, customerId || null, subscriptionId || null, status, periodEnd || null, now(), row.id]
    );
  } else {
    await execute(
      `INSERT INTO subscriptions (id, user_id, stripe_customer_id, stripe_subscription_id, status, current_period_end, created_at, updated_at)
       VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
      [ulid(), userId || null, customerId || null, subscriptionId || null, status, periodEnd || null, now(), now()]
    );
  }
}

router.post('/', async (req, res) => {
  if (!stripe || !config.stripe.webhookSecret) return res.status(503).send('billing not configured');
  let event;
  try {
    event = stripe.webhooks.constructEvent(req.body, req.headers['stripe-signature'], config.stripe.webhookSecret);
  } catch (err) {
    return res.status(400).send(`Webhook signature verification failed: ${err.message}`);
  }
  try {
    const o = event.data.object;
    if (event.type === 'checkout.session.completed') {
      await upsertSub({
        userId: o.client_reference_id || (o.metadata && o.metadata.user_id) || null,
        customerId: o.customer || null,
        subscriptionId: o.subscription || null,
        status: 'active',
        periodEnd: null,
      });
    } else if (event.type.startsWith('customer.subscription.')) {
      const status = event.type === 'customer.subscription.deleted' ? 'canceled' : o.status;
      await upsertSub({
        userId: (o.metadata && o.metadata.user_id) || null,
        customerId: o.customer || null,
        subscriptionId: o.id || null,
        status,
        periodEnd: o.current_period_end || null,
      });
    }
    res.json({ received: true });
  } catch (err) {
    console.error('stripe webhook handler error:', err.message);
    res.status(500).send('handler error');
  }
});

export default router;
