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

vi.mock('../../lib/prisma', () => ({ prisma: {} }))
vi.mock('../../lib/redis', () => ({
  redis: { on: vi.fn(), get: vi.fn(), set: vi.fn(), del: vi.fn(), quit: vi.fn() },
}))

vi.mock('../../middleware/requireRenterAuth', () => ({
  requireRenterAuth: (req: any, _res: any, next: any) => {
    req.renterId = 'renter_1'
    next()
  },
  optionalRenterAuth: (_req: any, _res: any, next: any) => next(),
}))

vi.mock('../../modules/site/site.service', () => ({
  getPlatformHomepage: vi.fn(),
  getPlatformPricing: vi.fn(),
  getBrand: vi.fn(),
  getPublicVehicles: vi.fn(),
  getVehicleDetail: vi.fn(),
  getOffers: vi.fn(),
  getBookingOptions: vi.fn(),
  checkAvailability: vi.fn(),
  validatePromoCode: vi.fn(),
  createBooking: vi.fn(),
  getBooking: vi.fn(),
  initPayment: vi.fn(),
  capturePaypal: vi.fn(),
  handleContact: vi.fn(),
}))

vi.mock('../../modules/carplace/carplace.service', () => ({
  getPublicOffers: vi.fn(),
  getCities: vi.fn(),
  getListedCompanies: vi.fn(),
  searchVehicles: vi.fn(),
  searchVehiclesPage: vi.fn(),
  createCarplaceReservation: vi.fn(),
  getReviewContext: vi.fn(),
  submitReview: vi.fn(),
  validateOfferCode: vi.fn(),
  getCompanyPage: vi.fn(),
  getCompanyReviews: vi.fn(),
  getCompanyVehicles: vi.fn(),
  getVehicleDetail: vi.fn(),
  getCompanyOffers: vi.fn(),
}))

import request from 'supertest'
import { createApp } from '../../app'
import * as siteService from '../../modules/site/site.service'
import * as carplaceService from '../../modules/carplace/carplace.service'

const app = createApp()

describe('public validation API contracts', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    vi.mocked(siteService.checkAvailability).mockResolvedValue({ available: true, nextAvailableAt: null } as never)
    vi.mocked(siteService.initPayment).mockResolvedValue({ checkoutUrl: 'https://pay.example.test' } as never)
    vi.mocked(siteService.handleContact).mockResolvedValue({ success: true } as never)
    vi.mocked(carplaceService.searchVehiclesPage).mockResolvedValue({
      items: [],
      pagination: { page: 2, pageSize: 30, totalItems: 0, totalPages: 0 },
      facets: { categories: [], transmissions: [], makes: [], price: { min: null, max: null } },
    } as never)
    vi.mocked(carplaceService.createCarplaceReservation).mockResolvedValue({ id: 'reservation_1' } as never)
    vi.mocked(carplaceService.submitReview).mockResolvedValue({ id: 'review_1' } as never)
  })

  it('rejects malformed public availability checks before site service execution', async () => {
    const res = await request(app).post('/api/v1/site/atlas-cars/availability').send({
      vehicleId: 'not-a-cuid',
      startDate: '2026-07-01',
      endDate: 'tomorrow-ish',
    })

    expect(res.status).toBe(400)
    expect(res.body).toMatchObject({ error: 'validation_error', statusCode: 400 })
    expect(siteService.checkAvailability).not.toHaveBeenCalled()
  })

  it('accepts valid public availability payloads and passes parsed fields explicitly', async () => {
    const payload = {
      vehicleId: 'ckvvehicle000000000000001',
      startDate: '2026-07-01T10:00:00.000Z',
      endDate: '2026-07-03T10:00:00.000Z',
    }

    const res = await request(app).post('/api/v1/site/atlas-cars/availability').send(payload)

    expect(res.status).toBe(200)
    expect(res.body).toEqual({ data: { available: true, nextAvailableAt: null } })
    expect(siteService.checkAvailability).toHaveBeenCalledWith('atlas-cars', payload.vehicleId, payload.startDate, payload.endDate)
  })

  it('rejects unsupported public payment providers before payment initialization', async () => {
    const res = await request(app).post('/api/v1/site/atlas-cars/booking/reservation_1/pay').send({
      provider: 'STRIPE',
      successUrl: 'https://example.test/success',
      failureUrl: 'https://example.test/fail',
      accessToken: 'booking-access-token-123',
    })

    expect(res.status).toBe(400)
    expect(siteService.initPayment).not.toHaveBeenCalled()
  })

  it('defaults site payment currency to MAD for valid public payment requests', async () => {
    const res = await request(app).post('/api/v1/site/atlas-cars/booking/reservation_1/pay').send({
      provider: 'PAYPAL',
      successUrl: 'https://example.test/success',
      failureUrl: 'https://example.test/fail',
      accessToken: 'booking-access-token-123',
    })

    expect(res.status).toBe(200)
    expect(siteService.initPayment).toHaveBeenCalledWith('atlas-cars', 'reservation_1', {
      provider: 'PAYPAL',
      currency: 'MAD',
      successUrl: 'https://example.test/success',
      failureUrl: 'https://example.test/fail',
      accessToken: 'booking-access-token-123',
    })
  })

  it('coerces carplace search pagination and price filters', async () => {
    const res = await request(app).get('/api/v1/carplace/search?city=Rabat&maxPrice=500&page=2&pageSize=30')

    expect(res.status).toBe(200)
    expect(carplaceService.searchVehiclesPage).toHaveBeenCalledWith({
      city: 'Rabat',
      maxPrice: 500,
      page: 2,
      pageSize: 30,
    })
    expect(res.body.data.pagination).toEqual({ page: 2, pageSize: 30, totalItems: 0, totalPages: 0 })
  })

  it('rejects oversized carplace pagination before search execution', async () => {
    const res = await request(app).get('/api/v1/carplace/search?pageSize=500')

    expect(res.status).toBe(400)
    expect(carplaceService.searchVehiclesPage).not.toHaveBeenCalled()
  })

  it('rejects carplace reservations with invalid public contact data before service execution', async () => {
    const res = await request(app).post('/api/v1/carplace/reservations').send({
      vehicleId: 'ckvvehicle000000000000001',
      companySlug: 'atlas-cars',
      firstName: 'Aya',
      lastName: 'Benali',
      email: 'bad-email',
      startDate: '2026-07-01T10:00:00.000Z',
      endDate: '2026-07-03T10:00:00.000Z',
    })

    expect(res.status).toBe(400)
    expect(carplaceService.createCarplaceReservation).not.toHaveBeenCalled()
  })

  it('rejects invalid public review ratings before creating reviews', async () => {
    const res = await request(app).post('/api/v1/carplace/review/token_1').send({ overallRating: 6 })

    expect(res.status).toBe(400)
    expect(carplaceService.submitReview).not.toHaveBeenCalled()
  })
})
