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

vi.mock('../lib/prisma', () => ({
  prisma: {
    pricingRule: {
      findMany: vi.fn(),
    },
    customer: {
      findFirstOrThrow: vi.fn(),
      findUniqueOrThrow: vi.fn(),
    },
  },
}))

import { prisma } from '../lib/prisma'
import { applyPricingRules } from './pricingRuleService'

describe('applyPricingRules', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    vi.setSystemTime(new Date('2026-06-08T12:00:00.000Z'))
  })

  it('applies percentage, flat-per-day, and flat pricing rules against the rental base amount', async () => {
    vi.mocked(prisma.customer.findFirstOrThrow).mockResolvedValue({
      id: 'customer_1',
      dateOfBirth: new Date('2008-06-09T00:00:00.000Z'),
      licenseIssuedAt: new Date('2025-06-09T00:00:00.000Z'),
    } as never)
    vi.mocked(prisma.pricingRule.findMany).mockResolvedValue([
      {
        id: 'young_driver_fee',
        name: 'Young driver fee',
        condition: 'AGE_LESS_THAN',
        conditionValue: 21,
        adjustmentType: 'PERCENTAGE',
        adjustmentValue: 10,
        type: 'SURCHARGE',
      },
      {
        id: 'new_license_fee',
        name: 'New license fee',
        condition: 'LICENSE_YEARS_LESS_THAN',
        conditionValue: 2,
        adjustmentType: 'FLAT_PER_DAY',
        adjustmentValue: 50,
        type: 'SURCHARGE',
      },
      {
        id: 'senior_discount',
        name: 'Senior discount',
        condition: 'AGE_GREATER_THAN',
        conditionValue: 60,
        adjustmentType: 'FLAT',
        adjustmentValue: 100,
        type: 'DISCOUNT',
      },
    ] as never)

    const result = await applyPricingRules('company_1', 'customer_1', [
      { dateOfBirth: new Date('1950-01-01T00:00:00.000Z'), licenseIssuedAt: new Date('1980-01-01T00:00:00.000Z') },
    ], 200, 3)

    expect(prisma.pricingRule.findMany).toHaveBeenCalledWith({ where: { companyId: 'company_1', isActive: true } })
    expect(result.applied).toEqual([
      { ruleId: 'young_driver_fee', name: 'Young driver fee', type: 'SURCHARGE', amount: 60 },
      { ruleId: 'new_license_fee', name: 'New license fee', type: 'SURCHARGE', amount: 150 },
      { ruleId: 'senior_discount', name: 'Senior discount', type: 'DISCOUNT', amount: -100 },
    ])
    expect(result.total).toBe(110)
  })

  it('deduplicates a rule when multiple drivers qualify', async () => {
    vi.mocked(prisma.customer.findFirstOrThrow).mockResolvedValue({
      id: 'customer_1',
      dateOfBirth: new Date('2006-01-01T00:00:00.000Z'),
      licenseIssuedAt: null,
    } as never)
    vi.mocked(prisma.pricingRule.findMany).mockResolvedValue([
      {
        id: 'young_driver_fee',
        name: 'Young driver fee',
        condition: 'AGE_LESS_THAN',
        conditionValue: 25,
        adjustmentType: 'FLAT',
        adjustmentValue: 75,
        type: 'SURCHARGE',
      },
    ] as never)

    const result = await applyPricingRules('company_1', 'customer_1', [
      { dateOfBirth: new Date('2007-01-01T00:00:00.000Z'), licenseIssuedAt: null },
    ], 100, 5)

    expect(result.applied).toHaveLength(1)
    expect(result.total).toBe(75)
  })

  it('ignores rules when required driver data is missing', async () => {
    vi.mocked(prisma.customer.findFirstOrThrow).mockResolvedValue({
      id: 'customer_1',
      dateOfBirth: null,
      licenseIssuedAt: null,
    } as never)
    vi.mocked(prisma.pricingRule.findMany).mockResolvedValue([
      {
        id: 'license_rule',
        name: 'Experienced license discount',
        condition: 'LICENSE_YEARS_GREATER_THAN',
        conditionValue: 10,
        adjustmentType: 'PERCENTAGE',
        adjustmentValue: 5,
        type: 'DISCOUNT',
      },
    ] as never)

    const result = await applyPricingRules('company_1', 'customer_1', [], 100, 2)

    expect(result).toEqual({ applied: [], total: 0 })
  })
})
