/* test/_stripeMock.js
 *
 * Shared Stripe SDK mock. Both test/billing.test.js and
 * test/billingAnnual.test.js require this BEFORE routes/billing so
 * the route captures the same `mockStripe` reference in both files.
 *
 * Exports:
 *   - mockStripe  : the mocked SDK with all the methods we exercise
 *   - lastSessionCreate : captured `params` from the most recent
 *                          stripe.checkout.sessions.create() call
 *   - sign(payload, secret) : builds a valid Stripe webhook signature
 *   - reset()      : clears lastSessionCreate between tests
 */

'use strict';

const crypto = require('crypto');

const lastSessionCreate = { value: null };

const mockStripe = {
  customers: {
    create: async (params) => ({
      id: 'cus_mock_' + Math.random().toString(36).slice(2, 10),
      email: params.email, name: params.name, metadata: params.metadata || {},
    }),
  },
  checkout: {
    sessions: {
      create: async (params) => {
        lastSessionCreate.value = params;
        return {
          id: 'cs_test_mock_' + Math.random().toString(36).slice(2, 10),
          url: 'https://checkout.stripe.com/c/pay/cs_test_mock_' + Math.random().toString(36).slice(2, 10),
          customer: params.customer,
          mode: params.mode,
          metadata: params.metadata,
          subscription: 'sub_mock_' + Math.random().toString(36).slice(2, 10),
        };
      },
    },
  },
  billingPortal: {
    sessions: {
      create: async (params) => ({
        id: 'bps_mock_' + Math.random().toString(36).slice(2, 10),
        url: 'https://billing.stripe.com/p/session/' + Math.random().toString(36).slice(2, 10),
        customer: params.customer, return_url: params.return_url,
      }),
    },
  },
  webhooks: {
    constructEvent: (payload, header, secret) => {
      const ts = parseInt((header.match(/t=(\d+)/) || [])[1], 10);
      const v1 = (header.match(/v1=([a-f0-9]+)/) || [])[1];
      if (!ts || !v1) throw new Error('Malformed signature header');
      const expected = crypto.createHmac('sha256', secret).update(ts + '.' + payload).digest('hex');
      // Stripe signatures are equal length; bail on mismatch without timingSafe
      // if buffer sizes differ to avoid the throw the test infra expects.
      if (expected.length !== v1.length) throw new Error('Signature mismatch');
      if (!crypto.timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(v1, 'hex'))) {
        throw new Error('Signature mismatch');
      }
      return JSON.parse(payload);
    },
  },
};

function installMock() {
  const stripePath = require.resolve('../config/stripe');
  require.cache[stripePath] = {
    id: stripePath, filename: stripePath, loaded: true,
    exports: mockStripe,
  };
}

function reset() {
  lastSessionCreate.value = null;
}

function sign(payload, secret, ts = Math.floor(Date.now() / 1000)) {
  const sig = crypto.createHmac('sha256', secret).update(ts + '.' + payload).digest('hex');
  return { header: 't=' + ts + ',v1=' + sig, ts };
}

module.exports = {
  mockStripe,
  installMock,
  reset,
  sign,
  get lastSessionCreate() { return lastSessionCreate.value; },
};
