/**
 * S9-005 subscription webhook idempotency regression tests.
 */
import { describe, it, expect, vi, beforeEach } from 'vitest'
import {
  resolveSubscriptionWebhookEventId,
  subscriptionWebhookIdemKey,
  isSubscriptionWebhookDuplicate,
  markSubscriptionWebhookProcessed,
} from '../src/lib/subscription-webhook-idempotency'

describe('subscription webhook idempotency', () => {
  beforeEach(() => {
    vi.clearAllMocks()
  })

  it('uses provider eventId when present', async () => {
    const id = await resolveSubscriptionWebhookEventId(
      { type: 'invoice.paid', eventId: 'evt_abc123' },
      '{"foo":1}',
    )
    expect(id).toBe('evt_abc123')
  })

  it('falls back to payload hash when eventId absent', async () => {
    const id1 = await resolveSubscriptionWebhookEventId(
      { type: 'invoice.paid' },
      '{"tenant":"t1"}',
    )
    const id2 = await resolveSubscriptionWebhookEventId(
      { type: 'invoice.paid' },
      '{"tenant":"t1"}',
    )
    expect(id1).toBe(id2)
    expect(id1).toHaveLength(64)
  })

  it('detects duplicate events in KV', async () => {
    const kv = {
      get: vi.fn().mockResolvedValueOnce(null).mockResolvedValueOnce('1'),
      put: vi.fn().mockResolvedValue(undefined),
    } as unknown as KVNamespace

    const eventId = 'evt_dup'
    expect(await isSubscriptionWebhookDuplicate(kv, eventId)).toBe(false)
    await markSubscriptionWebhookProcessed(kv, eventId)
    expect(kv.put).toHaveBeenCalledWith(subscriptionWebhookIdemKey(eventId), '1', {
      expirationTtl: 60 * 60 * 24 * 30,
    })
    expect(await isSubscriptionWebhookDuplicate(kv, eventId)).toBe(true)
  })
})
