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

vi.mock('../../lib/prisma', () => ({
  prisma: {
    reservation: {
      findMany: vi.fn(),
      count: vi.fn(),
      findFirst: vi.fn(),
      findFirstOrThrow: vi.fn(),
      create: vi.fn(),
      update: vi.fn(),
    },
    offer: {
      findFirst: vi.fn(),
      update: vi.fn(),
    },
    vehicle: {
      findFirstOrThrow: vi.fn(),
      update: vi.fn(),
    },
    customer: {
      findFirstOrThrow: vi.fn(),
      findUniqueOrThrow: vi.fn(),
    },
    company: { findUnique: vi.fn() },
    brandSettings: { findUnique: vi.fn() },
    damageInspection: { findMany: vi.fn() },
    additionalDriver: { findFirstOrThrow: vi.fn(), update: vi.fn() },
  },
}))

import { prisma } from '../../lib/prisma'
import * as repo from './reservation.repo'

describe('reservation.repo edge queries', () => {
  beforeEach(() => vi.clearAllMocks())

  it('findMany applies dashboard include, pagination and newest-first ordering', async () => {
    vi.mocked(prisma.reservation.findMany).mockResolvedValue([{ id: 'reservation_1' }] as never)
    vi.mocked(prisma.reservation.count).mockResolvedValue(1 as never)

    await expect(repo.findMany({ companyId: 'company_1' }, 20, 10)).resolves.toEqual([[{ id: 'reservation_1' }], 1])

    expect(prisma.reservation.findMany).toHaveBeenCalledWith({
      where: { companyId: 'company_1' },
      include: { vehicle: true, customer: true },
      skip: 20,
      take: 10,
      orderBy: { createdAt: 'desc' },
    })
    expect(prisma.reservation.count).toHaveBeenCalledWith({ where: { companyId: 'company_1' } })
  })

  it('builds overlap conflict query and excludes current reservation during updates', async () => {
    const start = new Date('2026-09-01T10:00:00.000Z')
    const end = new Date('2026-09-03T10:00:00.000Z')

    await repo.findConflict('vehicle_1', start, end, 'reservation_1')

    expect(prisma.reservation.findFirst).toHaveBeenCalledWith({
      where: {
        vehicleId: 'vehicle_1',
        status: { in: ['CONFIRMED', 'ACTIVE'] },
        startDate: { lt: end },
        endDate: { gt: start },
        id: { not: 'reservation_1' },
      },
    })
  })

  it('finds active offers by company, code, active flag and current validity window', async () => {
    vi.useFakeTimers()
    vi.setSystemTime(new Date('2026-09-15T12:00:00.000Z'))

    await repo.findActiveOffer('company_1', 'SUMMER20')

    expect(prisma.offer.findFirst).toHaveBeenCalledWith({
      where: {
        companyId: 'company_1',
        promoCode: 'SUMMER20',
        isActive: true,
        validFrom: { lte: new Date('2026-09-15T12:00:00.000Z') },
        validUntil: { gte: new Date('2026-09-15T12:00:00.000Z') },
      },
    })

    vi.useRealTimers()
  })

  it('updates vehicle status without writing mileage unless explicitly supplied', async () => {
    await repo.updateVehicleStatus('vehicle_1', 'AVAILABLE')
    expect(prisma.vehicle.update).toHaveBeenLastCalledWith({ where: { id: 'vehicle_1' }, data: { status: 'AVAILABLE' } })

    await repo.updateVehicleStatus('vehicle_1', 'AVAILABLE', 45500)
    expect(prisma.vehicle.update).toHaveBeenLastCalledWith({
      where: { id: 'vehicle_1' },
      data: { status: 'AVAILABLE', mileage: 45500 },
    })
  })
})
