import request from 'supertest'
import { prisma } from '../../lib/prisma'
import { createApp } from '../../app'
import {
  authHeader,
  createCompanyWithEmployee,
  createCustomer,
  createRentalPayment,
  createReservation,
  createVehicle,
  signEmployeeToken,
} from '../helpers/fixtures'


const app = createApp()

function uniqueEmail(prefix: string) {
  return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}@test.com`
}

describe('Payment webhooks — signature bypass fix (VF-02)', () => {
  describe('POST /api/v1/payments/webhooks/amanpay', () => {
    it('returns 401 when AmanPay is not configured (env vars absent)', async () => {
      // In the test environment AMANPAY_MERCHANT_ID and AMANPAY_SECRET_KEY are not set,
      // so isConfigured() returns false. The fix ensures this returns 401, not 200.
      const res = await request(app)
        .post('/api/v1/payments/webhooks/amanpay')
        .send({ transaction_id: 'txn_fake', status: 'PAID' })

      expect(res.status).toBe(401)
      expect(res.body.error).toBe('invalid_signature')
    })

    it('does not process the webhook payload when provider is not configured', async () => {
      const { company, employee } = await createCompanyWithEmployee({ role: 'OWNER' })
      const vehicle   = await createVehicle(company.id)
      const customer  = await createCustomer(company.id)
      const reservation = await createReservation(company.id, vehicle.id, customer.id, {
        totalAmount: 1000, paidAmount: 0,
      })
      const payment = await createRentalPayment(company.id, reservation.id, {
        status: 'PENDING',
        amanpayTransactionId: `txn-webhook-${Date.now()}`,
      })

      const res = await request(app)
        .post('/api/v1/payments/webhooks/amanpay')
        .send({ transaction_id: payment.amanpayTransactionId, status: 'PAID' })

      expect(res.status).toBe(401)

      // Reservation must remain unpaid — the handler was not invoked
      const unchanged = await prisma.reservation.findUniqueOrThrow({ where: { id: reservation.id } })
      expect(unchanged.paymentStatus).toBe('UNPAID')
    })
  })

  describe('POST /api/v1/payments/webhooks/paypal', () => {
    it('returns 401 when PayPal is not configured (env vars absent)', async () => {
      const res = await request(app)
        .post('/api/v1/payments/webhooks/paypal')
        .send({ event_type: 'PAYMENT.CAPTURE.COMPLETED', resource: { id: 'pp-fake' } })

      expect(res.status).toBe(401)
      expect(res.body.error).toBe('invalid_signature')
    })
  })
})

describe('Payments API', () => {
  let companyId: string
  let ownerToken: string
  let agentToken: string

  beforeAll(async () => {
    const { company, employee } = await createCompanyWithEmployee({ role: 'OWNER' })
    companyId = company.id
    ownerToken = signEmployeeToken(employee.id, companyId, 'OWNER')

    const agent = await prisma.employee.create({
      data: {
        companyId,
        clerkUserId: `clerk_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
        firstName: 'Agent',
        lastName:  'User',
        email:     uniqueEmail('agent'),
        role:      'AGENT',
      },
    })
    agentToken = signEmployeeToken(agent.id, companyId, 'AGENT')
  })

  describe('GET /api/v1/payments/company', () => {
    it('returns 401 without auth', async () => {
      const res = await request(app).get('/api/v1/payments/company')
      expect(res.status).toBe(401)
    })

    it('returns company payments', async () => {
      const vehicle = await createVehicle(companyId)
      const customer = await createCustomer(companyId)
      const reservation = await createReservation(companyId, vehicle.id, customer.id)
      const payment = await createRentalPayment(companyId, reservation.id)

      const res = await request(app)
        .get('/api/v1/payments/company')
        .set(authHeader(ownerToken))

      expect(res.status).toBe(200)
      expect(Array.isArray(res.body.data)).toBe(true)
      expect(res.body.data.some((item: any) => item.id === payment.id)).toBe(true)
    })
  })

  describe('POST /api/v1/payments/reservations/:id/manual', () => {
    it('records a manual payment and updates the reservation balance', async () => {
      const vehicle = await createVehicle(companyId)
      const customer = await createCustomer(companyId)
      const reservation = await createReservation(companyId, vehicle.id, customer.id, {
        totalAmount: 1200,
        paidAmount:  0,
      })

      const res = await request(app)
        .post(`/api/v1/payments/reservations/${reservation.id}/manual`)
        .set(authHeader(ownerToken))
        .send({
          amount:        400,
          currency:      'MAD',
          type:          'CHARGE',
          paymentMethod: 'CASH',
        })

      expect(res.status).toBe(200)
      expect(res.body.data.amount).toBe(400)
      expect(res.body.data.status).toBe('SUCCEEDED')

      const updated = await prisma.reservation.findUniqueOrThrow({ where: { id: reservation.id } })
      expect(updated.paidAmount).toBe(400)
      expect(updated.paymentStatus).toBe('PARTIAL')
    })

    it('returns 403 for AGENT role', async () => {
      const vehicle = await createVehicle(companyId)
      const customer = await createCustomer(companyId)
      const reservation = await createReservation(companyId, vehicle.id, customer.id)

      const res = await request(app)
        .post(`/api/v1/payments/reservations/${reservation.id}/manual`)
        .set(authHeader(agentToken))
        .send({
          amount:        300,
          currency:      'MAD',
          type:          'CHARGE',
          paymentMethod: 'CASH',
        })

      expect(res.status).toBe(403)
    })
  })

  describe('POST /api/v1/payments/reservations/:id/charge', () => {
    it('returns 409 when the reservation is already fully paid', async () => {
      const vehicle = await createVehicle(companyId)
      const customer = await createCustomer(companyId)
      const reservation = await createReservation(companyId, vehicle.id, customer.id, {
        totalAmount:   900,
        paidAmount:    900,
        paymentStatus: 'PAID',
      })

      const res = await request(app)
        .post(`/api/v1/payments/reservations/${reservation.id}/charge`)
        .set(authHeader(ownerToken))
        .send({
          provider:   'PAYPAL',
          type:       'CHARGE',
          currency:   'MAD',
          successUrl: 'https://example.com/success',
          failureUrl: 'https://example.com/failure',
        })

      expect(res.status).toBe(409)
      expect(res.body.error).toBe('conflict')
    })
  })

  describe('POST /api/v1/payments/reservations/:reservationId/payments/:paymentId/refund', () => {
    it('rejects refunding a manual payment through the gateway flow', async () => {
      const vehicle = await createVehicle(companyId)
      const customer = await createCustomer(companyId)
      const reservation = await createReservation(companyId, vehicle.id, customer.id)
      const payment = await createRentalPayment(companyId, reservation.id, {
        paymentMethod:        'CASH',
        paymentProvider:      'AMANPAY',
        amanpayTransactionId: null,
        paypalCaptureId:      null,
      })

      const res = await request(app)
        .post(`/api/v1/payments/reservations/${reservation.id}/payments/${payment.id}/refund`)
        .set(authHeader(ownerToken))
        .send({ amount: 100, reason: 'Test refund' })

      expect(res.status).toBe(400)
      expect(res.body.message).toContain('Manual payments')
    })
  })
})
