# Payments Framework

Ce répertoire fournit un **wrapper autour de [Stripe](https://stripe.com)** pour la gestion des paiements : sessions de checkout, intents, clients, remboursements et webhooks.

---

## Structure

```
src/core/payments/
├── index.js     re-export
└── stripe.js    wrapper Stripe
```

---

## Import

```js
import {
  isEnabled,
  getPublishableKey,
  createCheckoutSession,
  createPaymentIntent,
  getCheckoutSession,
  getPaymentIntent,
  verifyWebhookSignature,
  createCustomer,
  getOrCreateCustomer,
  listPaymentMethods,
  createRefund,
} from '@zen/core/payments';
```

---

## Variables d'environnement

| Variable | Obligatoire | Description |
|----------|-------------|-------------|
| `STRIPE_SECRET_KEY` | Oui | Clé secrète Stripe (côté serveur) |
| `STRIPE_PUBLISHABLE_KEY` | Oui | Clé publique Stripe (côté client) |
| `STRIPE_WEBHOOK_SECRET` | Pour les webhooks | Secret de signature des webhooks Stripe |
| `ZEN_CURRENCY` | Non | Devise par défaut pour les payment intents (défaut : `cad`) |

---

## API

### `isEnabled()`

Retourne `true` si `STRIPE_SECRET_KEY` et `STRIPE_PUBLISHABLE_KEY` sont définis. Utiliser pour conditionner l'affichage des fonctionnalités de paiement.

```js
if (isEnabled()) {
  // afficher le bouton de paiement
}
```

---

### `getPublishableKey()`

Retourne la clé publique Stripe, ou `null` si absente. Passer au client pour initialiser Stripe.js ou `@stripe/react-stripe-js`.

```js
const key = getPublishableKey();
```

---

### `createCheckoutSession(options)`

Crée une session Stripe Checkout. Retourne la session Stripe.

```js
const session = await createCheckoutSession({
  lineItems: [{ price: 'price_xxx', quantity: 1 }],
  successUrl: 'https://example.com/success',
  cancelUrl: 'https://example.com/cancel',
  customerEmail: 'user@example.com',
  mode: 'payment',
});

// Rediriger l'utilisateur vers session.url
```

| Paramètre | Type | Description |
|-----------|------|-------------|
| `lineItems` | `object[]` | Lignes de commande Stripe |
| `successUrl` | `string` | URL de retour après paiement réussi |
| `cancelUrl` | `string` | URL de retour après annulation |
| `customerEmail` | `string` | Email pré-rempli dans le formulaire (optionnel) |
| `clientReferenceId` | `string` | Identifiant interne pour rapprochement (optionnel) |
| `metadata` | `object` | Métadonnées Stripe (optionnel) |
| `mode` | `string` | `'payment'`, `'subscription'` ou `'setup'` (défaut : `'payment'`) |

---

### `createPaymentIntent(options)`

Crée un PaymentIntent Stripe. Retourne le PaymentIntent.

```js
const intent = await createPaymentIntent({
  amount: 4999, // en centimes
  currency: 'eur',
  metadata: { orderId: '123' },
});
```

| Paramètre | Type | Description |
|-----------|------|-------------|
| `amount` | `number` | Montant en centimes |
| `currency` | `string` | Devise ISO (défaut : `ZEN_CURRENCY` ou `cad`) |
| `metadata` | `object` | Métadonnées Stripe (optionnel) |
| `automaticPaymentMethods` | `object` | Config des méthodes de paiement (défaut : `{ enabled: true }`) |

---

### `getCheckoutSession(sessionId)`

Récupère une session Checkout par son identifiant. À utiliser dans la route `successUrl` pour confirmer le paiement.

```js
const session = await getCheckoutSession(sessionId);
```

---

### `getPaymentIntent(paymentIntentId)`

Récupère un PaymentIntent par son identifiant.

```js
const intent = await getPaymentIntent(paymentIntentId);
```

---

### `verifyWebhookSignature(payload, signature)`

Vérifie la signature d'un webhook Stripe et retourne l'événement. Lève une erreur si la signature est invalide ou si `STRIPE_WEBHOOK_SECRET` est absent.

```js
// Next.js Route Handler
export async function POST(req) {
  const payload = await req.text();
  const signature = req.headers.get('stripe-signature');

  let event;
  try {
    event = await verifyWebhookSignature(payload, signature);
  } catch (err) {
    return new Response('Signature invalide', { status: 400 });
  }

  if (event.type === 'checkout.session.completed') {
    // traiter la commande
  }

  return new Response('OK');
}
```

Le `payload` doit être le corps brut de la requête (non parsé).

---

### `createCustomer(options)`

Crée un client Stripe. Retourne le client.

```js
const customer = await createCustomer({
  email: 'user@example.com',
  name: 'Jean Dupont',
  metadata: { userId: '42' },
});
```

---

### `getOrCreateCustomer(email, defaultData)`

Retourne le client Stripe existant pour cet email, ou en crée un nouveau. Utilise une clé d'idempotence dérivée de l'email pour limiter les doublons en cas d'appels concurrents.

```js
const customer = await getOrCreateCustomer('user@example.com', {
  name: 'Jean Dupont',
  metadata: { userId: '42' },
});
```

---

### `listPaymentMethods(customerId, type)`

Retourne la liste des méthodes de paiement d'un client.

```js
const methods = await listPaymentMethods(customer.id, 'card');
```

Le paramètre `type` est optionnel (défaut : `'card'`).

---

### `createRefund(options)`

Crée un remboursement. Retourne le remboursement Stripe.

```js
const refund = await createRefund({
  paymentIntentId: 'pi_xxx',
  amount: 1000, // partiel, en centimes (optionnel — total si absent)
  reason: 'requested_by_customer', // optionnel
});
```

| Paramètre | Type | Description |
|-----------|------|-------------|
| `paymentIntentId` | `string` | Identifiant du PaymentIntent à rembourser |
| `amount` | `number` | Montant en centimes (optionnel, remboursement total si absent) |
| `reason` | `string` | Raison Stripe : `duplicate`, `fraudulent`, `requested_by_customer` (optionnel) |
