import crypto from 'crypto'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'

const originalEnv = { ...process.env }

async function importService(env: Record<string, string | undefined> = {}) {
  vi.resetModules()
  process.env = { ...originalEnv, ...env }
  return import('./amanpayService')
}

describe('amanpayService', () => {
  beforeEach(() => {
    vi.restoreAllMocks()
  })

  afterEach(() => {
    process.env = { ...originalEnv }
    vi.resetModules()
  })

  it('reports unconfigured when merchant credentials are placeholders or missing', async () => {
    const service = await importService({ AMANPAY_MERCHANT_ID: 'your-amanpay-merchant-id', AMANPAY_SECRET_KEY: 'secret' })
    expect(service.isConfigured()).toBe(false)
  })

  it('creates a checkout using merchant headers and maps alternate provider response fields', async () => {
    const fetchMock = vi.fn().mockResolvedValue({
      ok: true,
      json: vi.fn().mockResolvedValue({ id: 'txn_1', payment_url: 'https://pay.example/txn_1' }),
    })
    vi.stubGlobal('fetch', fetchMock)

    const service = await importService({
      AMANPAY_BASE_URL: 'https://amanpay.test',
      AMANPAY_MERCHANT_ID: 'merchant_1',
      AMANPAY_SECRET_KEY: 'secret_1',
    })

    await expect(service.createCheckout({
      amount: 12900,
      currency: 'MAD',
      orderId: 'order_1',
      description: 'Reservation payment',
      customerEmail: 'nora@example.com',
      customerName: 'Nora Saidi',
      successUrl: 'https://app.test/success',
      failureUrl: 'https://app.test/failure',
      webhookUrl: 'https://api.test/webhook',
    })).resolves.toEqual({
      transactionId: 'txn_1',
      checkoutUrl: 'https://pay.example/txn_1',
      status: 'PENDING',
    })

    expect(fetchMock).toHaveBeenCalledWith('https://amanpay.test/v1/payments', expect.objectContaining({
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-merchant-id': 'merchant_1',
        'x-api-key': 'secret_1',
      },
      body: expect.stringContaining('"order_id":"order_1"'),
    }))
  })

  it('turns provider checkout failures into useful errors', async () => {
    vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
      ok: false,
      statusText: 'Bad Request',
      json: vi.fn().mockResolvedValue({ message: 'invalid amount' }),
    }))
    const service = await importService({ AMANPAY_MERCHANT_ID: 'merchant_1', AMANPAY_SECRET_KEY: 'secret_1' })

    await expect(service.createCheckout({
      amount: 0,
      currency: 'MAD',
      orderId: 'order_1',
      description: 'Bad payment',
      successUrl: 'https://app.test/success',
      failureUrl: 'https://app.test/failure',
      webhookUrl: 'https://api.test/webhook',
    })).rejects.toThrow('AmanPay checkout failed: invalid amount')
  })

  it('verifies webhook signatures using the configured shared secret', async () => {
    const rawBody = JSON.stringify({ id: 'txn_1', status: 'PAID' })
    const signature = crypto.createHmac('sha256', 'webhook_secret').update(rawBody).digest('hex')
    const service = await importService({ AMANPAY_WEBHOOK_SECRET: 'webhook_secret' })

    expect(service.verifyWebhookSignature(rawBody, signature)).toBe(true)
    expect(service.verifyWebhookSignature(rawBody, crypto.createHmac('sha256', 'webhook_secret').update('other').digest('hex'))).toBe(false)
  })
})
