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

vi.mock('../lib/prisma', () => ({
  prisma: {
    insurancePolicy: { findMany: vi.fn() },
    reservationInsurance: { createMany: vi.fn() },
    reservation: { update: vi.fn() },
    $transaction: vi.fn(),
  },
}))

import { prisma } from '../lib/prisma'
import { applyInsurancesToReservation, calculateInsuranceCharge } from './insuranceService'

const policy = (overrides: Record<string, unknown>) => ({
  id: 'policy_1',
  companyId: 'company_1',
  name: 'Collision damage waiver',
  type: 'CDW',
  chargeType: 'PER_DAY',
  chargeValue: 100,
  isRequired: false,
  isActive: true,
  ...overrides,
}) as any

describe('insuranceService', () => {
  beforeEach(() => vi.clearAllMocks())

  it('calculates per-day, per-rental, percentage, and unknown insurance charges defensively', () => {
    expect(calculateInsuranceCharge(policy({ chargeType: 'PER_DAY', chargeValue: 25 }), 4, 1_000)).toBe(100)
    expect(calculateInsuranceCharge(policy({ chargeType: 'PER_RENTAL', chargeValue: 90 }), 4, 1_000)).toBe(90)
    expect(calculateInsuranceCharge(policy({ chargeType: 'PERCENTAGE_OF_RENTAL', chargeValue: 12.5 }), 4, 999)).toBe(125)
    expect(calculateInsuranceCharge(policy({ chargeType: 'WHO_KNOWS', chargeValue: 50 }), 4, 1_000)).toBe(0)
  })

  it('always applies required active policies and selected optional policies in one reservation transaction', async () => {
    vi.mocked(prisma.insurancePolicy.findMany).mockResolvedValue([
      policy({ id: 'required_1', name: 'Mandatory liability', isRequired: true, chargeType: 'PER_RENTAL', chargeValue: 300 }),
      policy({ id: 'optional_1', name: 'Glass cover', isRequired: false, chargeType: 'PER_DAY', chargeValue: 50 }),
      policy({ id: 'optional_2', name: 'Ignored cover', isRequired: false, chargeType: 'PER_DAY', chargeValue: 999 }),
    ] as never)
    vi.mocked(prisma.$transaction).mockResolvedValue([] as never)

    const result = await applyInsurancesToReservation('reservation_1', 'company_1', ['optional_1'], 3, 1_200)

    expect(result.insuranceTotal).toBe(450)
    expect(result.records.map((r) => r.insurancePolicyId)).toEqual(['required_1', 'optional_1'])
    expect(prisma.insurancePolicy.findMany).toHaveBeenCalledWith({ where: { companyId: 'company_1', isActive: true } })
    expect(prisma.reservationInsurance.createMany).toHaveBeenCalledWith({ data: result.records })
    expect(prisma.reservation.update).toHaveBeenCalledWith({
      where: { id: 'reservation_1' },
      data: { insuranceTotal: 450, totalAmount: { increment: 450 } },
    })
    expect(prisma.$transaction).toHaveBeenCalledWith([undefined, undefined])
  })
})
