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

vi.mock('../../lib/prisma', () => ({ prisma: {} }))
vi.mock('../../lib/redis', () => ({ redis: { on: vi.fn(), get: vi.fn(), set: vi.fn(), del: vi.fn(), quit: vi.fn() } }))

vi.mock('../../services/amanpayService', () => ({
  isConfigured: vi.fn(),
  verifyWebhookSignature: vi.fn(),
}))

vi.mock('../../services/paypalService', () => ({
  isConfigured: vi.fn(),
  verifyWebhookEvent: vi.fn(),
}))

vi.mock('../../modules/payments/payment.service', () => ({
  handleAmanpayWebhook: vi.fn(),
  handlePaypalWebhook: vi.fn(),
  listByCompany: vi.fn(),
  listByReservation: vi.fn(),
  initCharge: vi.fn(),
  capturePaypal: vi.fn(),
  recordManualPayment: vi.fn(),
  refundPayment: vi.fn(),
}))

import request from 'supertest'
import { createApp } from '../../app'
import * as amanpay from '../../services/amanpayService'
import * as paypal from '../../services/paypalService'
import * as service from '../../modules/payments/payment.service'

const app = createApp()

describe('payments API contract', () => {
  beforeEach(() => {
    vi.clearAllMocks()
  })

  it('rejects AmanPay webhooks when signature validation fails and does not invoke service handlers', async () => {
    vi.mocked(amanpay.isConfigured).mockReturnValue(true)
    vi.mocked(amanpay.verifyWebhookSignature).mockReturnValue(false)

    const payload = { transaction_id: 'txn_1', status: 'PAID' }
    const res = await request(app)
      .post('/api/v1/payments/webhooks/amanpay')
      .set('x-amanpay-signature', 'bad')
      .send(payload)

    expect(res.status).toBe(401)
    expect(res.body).toEqual({ error: 'invalid_signature' })
    expect(amanpay.verifyWebhookSignature).toHaveBeenCalledWith(JSON.stringify(payload), 'bad')
    expect(service.handleAmanpayWebhook).not.toHaveBeenCalled()
  })

  it('accepts valid AmanPay webhooks and delegates the exact payload', async () => {
    vi.mocked(amanpay.isConfigured).mockReturnValue(true)
    vi.mocked(amanpay.verifyWebhookSignature).mockReturnValue(true)

    const payload = { transaction_id: 'txn_1', status: 'PAID' }
    const res = await request(app)
      .post('/api/v1/payments/webhooks/amanpay')
      .set('x-amanpay-signature', 'good')
      .send(payload)

    expect(res.status).toBe(200)
    expect(res.body).toEqual({ received: true })
    expect(service.handleAmanpayWebhook).toHaveBeenCalledWith(payload, JSON.stringify(payload))
  })

  it('rejects PayPal webhooks when provider verification fails', async () => {
    vi.mocked(paypal.isConfigured).mockReturnValue(true)
    vi.mocked(paypal.verifyWebhookEvent).mockResolvedValue(false)

    const res = await request(app)
      .post('/api/v1/payments/webhooks/paypal')
      .set('paypal-transmission-id', 'transmission_1')
      .send({ event_type: 'PAYMENT.CAPTURE.COMPLETED', resource: { id: 'capture_1' } })

    expect(res.status).toBe(401)
    expect(res.body).toEqual({ error: 'invalid_signature' })
    expect(service.handlePaypalWebhook).not.toHaveBeenCalled()
  })

  it('accepts verified PayPal webhooks and delegates handling', async () => {
    vi.mocked(paypal.isConfigured).mockReturnValue(true)
    vi.mocked(paypal.verifyWebhookEvent).mockResolvedValue(true)

    const payload = { event_type: 'PAYMENT.CAPTURE.COMPLETED', resource: { id: 'capture_1' } }
    const res = await request(app)
      .post('/api/v1/payments/webhooks/paypal')
      .send(payload)

    expect(res.status).toBe(200)
    expect(res.body).toEqual({ received: true })
    expect(service.handlePaypalWebhook).toHaveBeenCalledWith(payload, JSON.stringify(payload))
  })

  it('keeps authenticated payment routes behind auth before any payment service call', async () => {
    const res = await request(app).get('/api/v1/payments/company')

    expect(res.status).toBe(401)
    expect(service.listByCompany).not.toHaveBeenCalled()
  })
})
