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

vi.mock('./carplace.repo', () => ({
  findCompanyPage: vi.fn(),
  findCompanyBySlug: vi.fn(),
  findCompanyReviews: vi.fn(),
  findCompanyVehicles: vi.fn(),
  findVehicleById: vi.fn(),
  findCompanyOffers: vi.fn(),
  findOfferByCode: vi.fn(),
}))
vi.mock('../../services/vehicleAvailabilityService', () => ({ getVehicleAvailabilitySummary: vi.fn() }))
vi.mock('../../services/notificationService', () => ({ sendNotification: vi.fn(), sendTransactionalEmail: vi.fn() }))
vi.mock('../../lib/emailTranslations', () => ({
  carplaceReservationEmail: { subject: vi.fn(), html: vi.fn(), text: vi.fn() },
}))

import * as repo from './carplace.repo'
import { getVehicleAvailabilitySummary } from '../../services/vehicleAvailabilityService'
import { getCompanyOffers, getCompanyPage, getCompanyReviews, getCompanyVehicles, getVehicleDetail, validateOfferCode } from './carplace.service'

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

describe('carplace.service public page edges', () => {
  it('enriches company page vehicles with availability without changing company metadata', async () => {
    const nextAvailableAt = new Date('2026-07-14T09:00:00.000Z')
    vi.mocked(repo.findCompanyPage).mockResolvedValue({
      id: 'company_1',
      name: 'Atlas Cars',
      vehicles: [{ id: 'vehicle_1', make: 'Dacia' }, { id: 'vehicle_2', make: 'Renault' }],
    } as any)
    vi.mocked(getVehicleAvailabilitySummary)
      .mockResolvedValueOnce({ available: false, status: 'RESERVED', nextAvailableAt, blockingReason: 'RESERVATION' })
      .mockResolvedValueOnce({ available: true, status: 'AVAILABLE', nextAvailableAt: null, blockingReason: null })

    const result = await getCompanyPage('atlas-cars')

    expect(result).toMatchObject({ id: 'company_1', name: 'Atlas Cars' })
    expect(result.vehicles).toEqual([
      expect.objectContaining({ id: 'vehicle_1', availability: false, availabilityStatus: 'RESERVED', nextAvailableAt }),
      expect.objectContaining({ id: 'vehicle_2', availability: true, availabilityStatus: 'AVAILABLE', nextAvailableAt: null }),
    ])
  })

  it('throws when a public company page cannot be found', async () => {
    vi.mocked(repo.findCompanyPage).mockResolvedValue(null)
    await expect(getCompanyPage('missing-company')).rejects.toThrow('Company not found')
  })

  it('resolves public company child resources through the company id, not the slug directly', async () => {
    vi.mocked(repo.findCompanyBySlug).mockResolvedValue({ id: 'company_1' } as any)
    vi.mocked(repo.findCompanyReviews).mockResolvedValue([{ id: 'review_1' }] as any)
    vi.mocked(repo.findCompanyVehicles).mockResolvedValue([{ id: 'vehicle_1' }] as any)
    vi.mocked(repo.findCompanyOffers).mockResolvedValue([{ id: 'offer_1' }] as any)

    await expect(getCompanyReviews('atlas-cars')).resolves.toEqual([{ id: 'review_1' }])
    await expect(getCompanyVehicles('atlas-cars')).resolves.toEqual([{ id: 'vehicle_1' }])
    await expect(getCompanyOffers('atlas-cars')).resolves.toEqual([{ id: 'offer_1' }])

    expect(repo.findCompanyReviews).toHaveBeenCalledWith('company_1')
    expect(repo.findCompanyVehicles).toHaveBeenCalledWith('company_1')
    expect(repo.findCompanyOffers).toHaveBeenCalledWith('company_1')
  })

  it('adds availability to vehicle detail responses', async () => {
    const nextAvailableAt = new Date('2026-12-01T00:00:00.000Z')
    vi.mocked(repo.findVehicleById).mockResolvedValue({ id: 'vehicle_1', make: 'Hyundai' } as any)
    vi.mocked(getVehicleAvailabilitySummary).mockResolvedValue({ available: false, status: 'MAINTENANCE', nextAvailableAt, blockingReason: 'BLOCK' })

    await expect(getVehicleDetail('atlas-cars', 'vehicle_1')).resolves.toEqual(expect.objectContaining({
      id: 'vehicle_1',
      availability: false,
      availabilityStatus: 'MAINTENANCE',
      nextAvailableAt,
    }))
  })

  it('rejects exhausted offer codes before returning them as valid', async () => {
    vi.mocked(repo.findOfferByCode).mockResolvedValue({ code: 'SUMMER', maxRedemptions: 10, redemptionCount: 10 } as any)

    await expect(validateOfferCode('SUMMER')).rejects.toThrow('maximum redemptions')
  })
})
