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

import { requireAuth } from '../../../server/utils/auth.js'
import { validateBody as importedValidateBody } from '../../../server/utils/validateBody.js'
import initPaymentHandler from '../../../server/api/helcim/initialize-payment.post.js'
import verifyPaymentHandler from '../../../server/api/helcim/verify-payment.post.js'
import { createMockEvent } from '../helpers/createMockEvent.js'

vi.mock('../../../server/utils/auth.js', () => ({ requireAuth: vi.fn() }))
vi.mock('../../../server/utils/validateBody.js', () => ({ validateBody: vi.fn() }))
vi.mock('../../../server/utils/schemas.js', () => ({ paymentVerifySchema: {} }))

// helcimInitializePaymentSchema is a Nitro auto-import used by validateBody
vi.stubGlobal('helcimInitializePaymentSchema', {})

const mockFetch = vi.fn()
vi.stubGlobal('fetch', mockFetch)

describe('initialize-payment endpoint', () => {
  beforeEach(() => {
    vi.clearAllMocks()
  })

  afterEach(() => {
    mockFetch.mockReset()
  })

  it('skips auth for event_ticket type', async () => {
    const body = {
      amount: 25,
      metadata: { type: 'event_ticket', eventTitle: 'Test Event', eventId: 'evt-1' }
    }
    globalThis.validateBody.mockResolvedValue(body)

    mockFetch.mockResolvedValue({
      ok: true,
      text: async () => JSON.stringify({ checkoutToken: 'ct-123', secretToken: 'st-456' })
    })

    const event = createMockEvent({
      method: 'POST',
      path: '/api/helcim/initialize-payment',
      body
    })

    await initPaymentHandler(event)

    expect(requireAuth).not.toHaveBeenCalled()
  })

  it('requires auth for non-event_ticket types', async () => {
    const body = { amount: 0, customerCode: 'code-1' }
    globalThis.validateBody.mockResolvedValue(body)
    requireAuth.mockResolvedValue(undefined)

    mockFetch.mockResolvedValue({
      ok: true,
      text: async () => JSON.stringify({ checkoutToken: 'ct-123', secretToken: 'st-456' })
    })

    const event = createMockEvent({
      method: 'POST',
      path: '/api/helcim/initialize-payment',
      body
    })

    await initPaymentHandler(event)

    expect(requireAuth).toHaveBeenCalledWith(event)
  })

  it('returns checkoutToken and secretToken on success', async () => {
    const body = {
      amount: 10,
      metadata: { type: 'event_ticket', eventTitle: 'Workshop', eventId: 'evt-2' }
    }
    globalThis.validateBody.mockResolvedValue(body)

    mockFetch.mockResolvedValue({
      ok: true,
      text: async () => JSON.stringify({ checkoutToken: 'ct-abc', secretToken: 'st-xyz' })
    })

    const event = createMockEvent({
      method: 'POST',
      path: '/api/helcim/initialize-payment',
      body
    })

    const result = await initPaymentHandler(event)

    expect(result).toEqual({
      success: true,
      checkoutToken: 'ct-abc',
      secretToken: 'st-xyz'
    })
  })
})

describe('verify-payment endpoint', () => {
  beforeEach(() => {
    vi.clearAllMocks()
  })

  afterEach(() => {
    mockFetch.mockReset()
  })

  it('requires auth', async () => {
    requireAuth.mockRejectedValue(
      createError({ statusCode: 401, statusMessage: 'Unauthorized' })
    )

    const event = createMockEvent({
      method: 'POST',
      path: '/api/helcim/verify-payment',
      body: { customerId: 'cust-1', cardToken: 'tok-1' }
    })

    await expect(verifyPaymentHandler(event)).rejects.toMatchObject({
      statusCode: 401,
      statusMessage: 'Unauthorized'
    })

    expect(requireAuth).toHaveBeenCalledWith(event)
  })

  it('validates with paymentVerifySchema', async () => {
    const body = { customerId: 'cust-1', cardToken: 'tok-1' }
    requireAuth.mockResolvedValue(undefined)
    importedValidateBody.mockResolvedValue(body)

    mockFetch.mockResolvedValue({
      ok: true,
      text: async () => JSON.stringify([{ cardToken: 'tok-1' }])
    })

    const event = createMockEvent({
      method: 'POST',
      path: '/api/helcim/verify-payment',
      body
    })

    await verifyPaymentHandler(event)

    expect(importedValidateBody).toHaveBeenCalledWith(event, expect.any(Object))
  })

  it('returns success when card token found', async () => {
    const body = { customerId: 'cust-1', cardToken: 'tok-match' }
    requireAuth.mockResolvedValue(undefined)
    importedValidateBody.mockResolvedValue(body)

    mockFetch.mockResolvedValue({
      ok: true,
      text: async () => JSON.stringify([
        { cardToken: 'tok-other' },
        { cardToken: 'tok-match' }
      ])
    })

    const event = createMockEvent({
      method: 'POST',
      path: '/api/helcim/verify-payment',
      body
    })

    const result = await verifyPaymentHandler(event)

    expect(result).toEqual({
      success: true,
      cardToken: 'tok-match',
      message: 'Payment verified with Helcim'
    })
  })

  it('returns 400 when card token not found', async () => {
    const body = { customerId: 'cust-1', cardToken: 'tok-missing' }
    requireAuth.mockResolvedValue(undefined)
    importedValidateBody.mockResolvedValue(body)

    mockFetch.mockResolvedValue({
      ok: true,
      text: async () => JSON.stringify([
        { cardToken: 'tok-aaa' },
        { cardToken: 'tok-bbb' }
      ])
    })

    const event = createMockEvent({
      method: 'POST',
      path: '/api/helcim/verify-payment',
      body
    })

    await expect(verifyPaymentHandler(event)).rejects.toMatchObject({
      statusCode: 400,
      statusMessage: 'Payment method not found or does not belong to this customer'
    })
  })
})
