/**
 * GUIDE D'INTÉGRATION - Système d'événements ShopEvent
 *
 * Ce guide explique comment intégrer le système ShopEvent dans vos services métier.
 */

/**
 * ÉTAPE 1 : Service métier (ex: order.service.ts)
 *
 * Pattern :
 * 1. Muter l'entité + incrémenter revision ATOMIQUEMENT
 * 2. Créer l'événement ShopEvent
 * 3. Émettre via WebSocket
 */

// ❌ MAUVAIS : revision incrémentée separément
async function updateOrderBad(orderId: string, status: string) {
  const order = await prisma.order.update({
    where: { id: orderId },
    data: { status }
  })
  // ⚠️ Oups ! revision n'a pas été incrémentée
  // ShopEvent et Order sont maintenant désynchronisés
}

// ✅ BON : revision incrémentée dans le même UPDATE
async function updateOrderGood(
  orderId: string,
  shopId: string,
  status: string,
  userId: string
) {
  // 1. Muter + incrémenter revision ATOMIQUEMENT
  const order = await prisma.order.update({
    where: { id: orderId },
    data: {
      status,
      revision: { increment: 1 }  // ← Crucial !
    }
  })

  // 2. Créer l'événement
  const event = await shopEventService.createEvent(
    shopId,
    "order.status_changed",
    { orderId, status },
    {
      entity: "Order",
      entityId: orderId,
      revision: order.revision,
      actorUserId: userId
    }
  )

  // 3. Émettre via WebSocket (voir étape 2 ci-dessous)
  // wsOrders.updateOrder(shopId, order)

  return order
}

/**
 * ÉTAPE 2 : Émission WebSocket (ex: src/ws/ws.orders.ts)
 *
 * Pattern :
 * 1. L'événement est déjà créé en base (ShopEvent)
 * 2. Émettre l'événement via Socket.IO vers la room shop
 * 3. Frontend recevra via WebSocket ET REST en cas de reconnexion
 */

// Structure existante ws/ws.orders.ts
export const wsOrders = {
  // Existant
  upsert(shopId: string, order: OrderDetailDto) {
    io.to(`shop:${shopId}`).emit("orders:upsert", { order })
  },

  // Nouveau : émettre un ShopEvent
  emitOrderCreated(shopId: string, event: ShopEvent) {
    io.to(`shop:${shopId}`).emit("shop:event", {
      shopId,
      seq: event.seq.toString(),
      type: event.type,
      entity: event.entity,
      entityId: event.entityId,
      revision: event.revision,
      payload: event.payload,
      createdAt: event.createdAt.toISOString()
    })
  }
}

/**
 * ÉTAPE 3 : Frontend - Recevois des événements via WebSocket
 *
 * Pattern :
 * 1. Socket.IO reçoit l'événement
 * 2. Handler `shop:event` est déclenché
 * 3. Frontend met à jour lastEventSeq
 * 4. Frontend applique le changement au store
 */

// src/socket/handlers/shop-events.ts (à créer)
import type { ShopEventPayload } from "ttm-shared"

export function attachShopEventHandlers(socket: Socket) {
  const sync = useSyncStore()
  const orders = useOrderStore()
  const products = useProductStore()
  // ... autres stores

  socket.on("shop:event", (event: ShopEventPayload) => {
    // 1. Persiste le numéro de séquence
    sync.updateLastEventSeq(event.seq)

    // 2. Route vers le handler approprié selon le type
    switch (event.type) {
      case "order.created":
        orders.applyOrderCreated(event.payload)
        break
      case "order.updated":
        orders.applyOrderUpdated(event.payload)
        break
      case "product.updated":
        products.applyProductUpdated(event.payload)
        break
      // ... autres types
    }
  })
}

/**
 * ÉTAPE 4 : Frontend - Reconstituer après reconnexion
 *
 * Pattern :
 * 1. Frontend se reconnecte
 * 2. triggerResync() est appelé automatiquement
 * 3. fetchMissingEvents() retourne les événements depuis lastSeq
 * 4. Frontend rejoue les événements manqués
 */

// src/core/socket.ts (déjà implémenté)
async function triggerResync(shopId: string) {
  const sync = useSyncStore()
  const result = await sync.fetchMissingEvents(shopId)

  if (result.status === 410) {
    // Historique expiré - demander snapshot complet
    // TODO: recharger depuis l'API
    sync.reset()
    return
  }

  // Rejouer les événements manqués
  for (const event of result.events) {
    // Émettre le même événement que le WebSocket aurait envoyé
    const payload: ShopEventPayload = {
      id: event.id,
      shopId: event.shopId,
      seq: event.seq,
      type: event.type as ShopEventType,
      entity: event.entity,
      entityId: event.entityId,
      revision: event.revision,
      payload: event.payload,
      createdAt: event.createdAt
    }
    // Traiter comme si reçu via WebSocket
    // (réutiliser la même logique que attachShopEventHandlers)
  }
}

/**
 * RÉSUMÉ DE L'INTÉGRATION
 *
 * Services métier (backend) :
 * ✅ Muter entité + revision atomiquement
 * ✅ Créer ShopEvent via shopEventService.createEvent()
 * ✅ Émettre via WebSocket
 *
 * WebSocket (backend) :
 * ✅ Émettre l'événement vers la room shop
 *
 * Frontend :
 * ✅ Recevoir et persister lastEventSeq
 * ✅ Appliquer changement au store
 * ✅ Sur reconnexion : fetchMissingEvents() + rejouer
 *
 * API REST :
 * ✅ Endpoint GET /shops/:id/events?since={seq}
 * ✅ Retourne 410 si historique expiré
 *
 * Résultat :
 * ✅ Synchronisation robuste même avec déconnexions
 * ✅ Détection automatique de divergence (revision)
 * ✅ Recovery automatique (exponential backoff)
 * ✅ Snapshot fallback (410 Gone)
 */

