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/subscriptions/subscription.service', () => ({
  getPlans: vi.fn(),
  getProviders: vi.fn(),
  getPlanFeatures: vi.fn(),
  handleAmanpayWebhook: vi.fn(),
  handlePaypalWebhook: 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/subscriptions/subscription.service'

const app = createApp()

describe('subscriptions public API', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    vi.mocked(service.getProviders).mockReturnValue({ amanpay: false, paypal: true })
    vi.mocked(service.getPlans).mockResolvedValue({ STARTER: { MONTHLY: { MAD: 9900 } } } as never)
    vi.mocked(service.getPlanFeatures).mockResolvedValue([
      { id: 'feature_1', plan: 'STARTER', label: 'Vehicles', sortOrder: 1 },
    ] as never)
  })

  it('GET /api/v1/subscriptions/providers exposes configured payment provider availability', async () => {
    const res = await request(app).get('/api/v1/subscriptions/providers')

    expect(res.status).toBe(200)
    expect(res.body).toEqual({ data: { amanpay: false, paypal: true } })
    expect(service.getProviders).toHaveBeenCalledOnce()
  })

  it('GET /api/v1/subscriptions/plans wraps plan pricing in the standard API envelope', async () => {
    const res = await request(app).get('/api/v1/subscriptions/plans')

    expect(res.status).toBe(200)
    expect(res.body).toEqual({ data: { STARTER: { MONTHLY: { MAD: 9900 } } } })
    expect(service.getPlans).toHaveBeenCalledOnce()
  })

  it('GET /api/v1/subscriptions/features returns plan feature rows through the public router', async () => {
    const res = await request(app).get('/api/v1/subscriptions/features')

    expect(res.status).toBe(200)
    expect(res.body.data).toEqual([
      { id: 'feature_1', plan: 'STARTER', label: 'Vehicles', sortOrder: 1 },
    ])
  })

  it('rejects AmanPay webhooks when provider config or signature validation fails', async () => {
    vi.mocked(amanpay.isConfigured).mockReturnValue(true)
    vi.mocked(amanpay.verifyWebhookSignature).mockReturnValue(false)

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

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

  it('accepts verified PayPal webhooks and delegates handling to the subscription service', 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/subscriptions/webhooks/paypal')
      .send(payload)

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