import { createHmac, timingSafeEqual } from 'node:crypto';

export class StripeGateway {
  constructor({ secretKey, webhookSecret, prices = {}, fetchImpl = fetch, now = Date.now } = {}) { Object.assign(this, { secretKey, webhookSecret, prices, fetchImpl, now }); }
  get enabled() { return typeof this.secretKey === 'string' && this.secretKey.startsWith('sk_') && typeof this.webhookSecret === 'string' && this.webhookSecret.startsWith('whsec_') && ['solo', 'team', 'business'].every(plan => /^price_[A-Za-z0-9]+$/.test(this.prices[plan] || '')) && new Set(Object.values(this.prices)).size === 3; }
  async request(method, route, body, idempotency) {
    if (!this.enabled) throw Object.assign(new Error('Paiement indisponible : configuration requise.'), { status: 503 });
    const response = await this.fetchImpl(`https://api.stripe.com/v1/${route}`, { method, headers: { Authorization: `Bearer ${this.secretKey}`, 'Stripe-Version': '2025-02-24.acacia', ...(body ? { 'Content-Type': 'application/x-www-form-urlencoded' } : {}), ...(idempotency ? { 'Idempotency-Key': idempotency } : {}) }, ...(body ? { body: new URLSearchParams(body).toString() } : {}), signal: AbortSignal.timeout(15000) });
    if (!response.ok) throw Object.assign(new Error('Le prestataire de paiement est indisponible.'), { status: 502 });
    return response.json();
  }
  customer(account) { return this.request('POST', 'customers', { email: account.email, 'metadata[relio_account]': account.id }, `relio-customer-${account.id}`); }
  checkout(customer, plan, accountId, origin, key) { return this.request('POST', 'checkout/sessions', { mode: 'subscription', customer, client_reference_id: accountId, 'line_items[0][price]': this.prices[plan], 'line_items[0][quantity]': '1', 'subscription_data[metadata][relio_account]': accountId, 'automatic_tax[enabled]': 'true', billing_address_collection: 'required', 'customer_update[address]': 'auto', 'tax_id_collection[enabled]': 'true', success_url: `${origin}/account?checkout=success`, cancel_url: `${origin}/account?checkout=cancelled` }, key); }
  portal(customer, origin) { return this.request('POST', 'billing_portal/sessions', { customer, return_url: `${origin}/account` }); }
  subscription(id) { return this.request('GET', `subscriptions/${encodeURIComponent(id)}?expand[]=latest_invoice`); }
  subscriptions(customer) { return this.request('GET', `subscriptions?customer=${encodeURIComponent(customer)}&status=all&limit=100&expand[]=data.latest_invoice`); }
  verifyWebhook(raw, header) {
    if (!this.enabled || !Buffer.isBuffer(raw) || typeof header !== 'string' || header.length > 4096) return false;
    const fields = header.split(',').map(field => field.trim().split('='));
    const times = fields.filter(([key]) => key === 't');
    if (times.length !== 1 || !/^\d+$/.test(times[0][1])) return false;
    const timestamp = Number(times[0][1]);
    if (!Number.isSafeInteger(timestamp) || Math.abs(this.now() / 1000 - timestamp) > 300) return false;
    const expected = createHmac('sha256', this.webhookSecret).update(`${timestamp}.`).update(raw).digest();
    return fields.some(([key, value]) => key === 'v1' && /^[a-f0-9]{64}$/.test(value || '') && timingSafeEqual(expected, Buffer.from(value, 'hex')));
  }
}
