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

vi.mock('../../lib/prisma', () => ({ prisma: {} }))
vi.mock('../../lib/storage', () => ({ uploadImage: vi.fn().mockResolvedValue('https://cdn.example.test/photo.jpg') }))
vi.mock('./vehicle.repo', () => ({
  create: vi.fn(),
  findFirst: vi.fn(),
  updateById: vi.fn(),
  findById: vi.fn(),
  findCalendarEvents: vi.fn(),
  createMaintenanceLog: vi.fn(),
  findPricingConfiguration: vi.fn(),
  updatePricingConfiguration: vi.fn(),
  createPriceHistory: vi.fn(),
}))

const repo = await import('./vehicle.repo')
const service = await import('./vehicle.service')

const vehicle = {
  id: 'vehicle_1',
  companyId: 'company_1',
  make: 'Toyota',
  model: 'Yaris',
  year: 2024,
  status: 'AVAILABLE',
  isPublished: true,
  dailyRate: 30000,
  photos: [],
  pickupLocations: ['Casablanca'],
  allowDifferentDropoff: true,
  dropoffLocations: ['Rabat'],
  createdAt: new Date('2026-01-01T00:00:00.000Z'),
  updatedAt: new Date('2026-01-01T00:00:00.000Z'),
}

beforeEach(() => vi.clearAllMocks())

describe('vehicle.service edge behavior', () => {
  it('deduplicates and trims location settings when creating vehicles', async () => {
    vi.mocked(repo.create).mockResolvedValue({ ...vehicle, pickupLocations: ['Casablanca', 'Rabat'], dropoffLocations: ['Airport'] } as any)

    await service.createVehicle({
      make: 'Toyota',
      pickupLocations: [' Casablanca ', 'casablanca', '', 42, 'Rabat'],
      allowDifferentDropoff: true,
      dropoffLocations: [' Airport ', 'airport', null],
    }, 'company_1')

    expect(repo.create).toHaveBeenCalledWith(expect.objectContaining({
      companyId: 'company_1',
      pickupLocations: ['Casablanca', 'Rabat'],
      allowDifferentDropoff: true,
      dropoffLocations: ['Airport'],
    }))
  })

  it('clears drop-off locations when different drop-off is disabled', async () => {
    vi.mocked(repo.findFirst).mockResolvedValue(vehicle as any)
    vi.mocked(repo.updateById).mockResolvedValue({ ...vehicle, allowDifferentDropoff: false, dropoffLocations: [] } as any)

    await service.updateVehicle('vehicle_1', 'company_1', {
      allowDifferentDropoff: false,
      dropoffLocations: ['Rabat'],
    })

    expect(repo.updateById).toHaveBeenCalledWith('vehicle_1', expect.objectContaining({
      allowDifferentDropoff: false,
      dropoffLocations: [],
    }))
  })

  it('rejects enabling different drop-off without any usable drop-off location', async () => {
    await expect(service.createVehicle({
      allowDifferentDropoff: true,
      dropoffLocations: [' ', null],
    }, 'company_1')).rejects.toThrow('Drop-off locations are required')

    expect(repo.create).not.toHaveBeenCalled()
  })

  it('builds calendar labels from customers and block reasons', async () => {
    vi.mocked(repo.findById).mockResolvedValue(vehicle as any)
    vi.mocked(repo.findCalendarEvents).mockResolvedValue([
      [{
        id: 'reservation_1',
        startDate: new Date('2026-09-01T00:00:00.000Z'),
        endDate: new Date('2026-09-03T00:00:00.000Z'),
        status: 'CONFIRMED',
        customer: { firstName: 'Aya', lastName: 'Benali' },
      }],
      [{
        id: 'block_1',
        startDate: new Date('2026-09-10T00:00:00.000Z'),
        endDate: new Date('2026-09-11T00:00:00.000Z'),
        type: 'MAINTENANCE',
        reason: null,
      }],
    ] as any)

    const result = await service.getCalendar('vehicle_1', 'company_1', 2026, 9)

    expect(repo.findCalendarEvents).toHaveBeenCalledWith(
      'vehicle_1',
      'company_1',
      new Date(2026, 8, 1),
      new Date(2026, 9, 1),
    )
    expect(result).toEqual(expect.arrayContaining([
      expect.objectContaining({ id: 'reservation_1', type: 'RESERVATION', label: 'Aya Benali' }),
      expect.objectContaining({ id: 'block_1', type: 'MAINTENANCE', label: 'Maintenance' }),
    ]))
  })

  it('normalizes maintenance log dates before persistence', async () => {
    vi.mocked(repo.findById).mockResolvedValue(vehicle as any)
    vi.mocked(repo.createMaintenanceLog).mockResolvedValue({ id: 'maintenance_1' } as any)

    await service.createMaintenanceLog('vehicle_1', 'company_1', {
      description: 'Oil change',
      performedAt: '2026-07-01T12:00:00.000Z',
      nextDueAt: '2026-10-01T12:00:00.000Z',
    })

    expect(repo.createMaintenanceLog).toHaveBeenCalledWith(expect.objectContaining({
      vehicleId: 'vehicle_1',
      performedAt: new Date('2026-07-01T12:00:00.000Z'),
      nextDueAt: new Date('2026-10-01T12:00:00.000Z'),
    }))
  })
})
