import request from 'supertest'
import { prisma } from '../../lib/prisma'
import { createApp } from '../../app'
import {
  createCompanyWithEmployee,
  createVehicle,
  signEmployeeToken,
  authHeader,
} from '../helpers/fixtures'

const app = createApp()

describe('Vehicles API', () => {
  let companyId: string
  let token: string

  beforeAll(async () => {
    const { company, employee } = await createCompanyWithEmployee({ role: 'OWNER' })
    companyId = company.id
    token = signEmployeeToken(employee.id, companyId, 'OWNER')
  })

  describe('GET /api/v1/vehicles', () => {
    it('returns 401 without auth', async () => {
      const res = await request(app).get('/api/v1/vehicles')
      expect(res.status).toBe(401)
    })

    it('returns paginated vehicle list', async () => {
      await createVehicle(companyId)
      await createVehicle(companyId)

      const res = await request(app)
        .get('/api/v1/vehicles')
        .set(authHeader(token))

      expect(res.status).toBe(200)
      expect(typeof res.body.total).toBe('number')
      expect(res.body.total).toBeGreaterThanOrEqual(2)
      expect(Array.isArray(res.body.data)).toBe(true)
    })

    it('filters by status', async () => {
      await createVehicle(companyId, { status: 'MAINTENANCE' })

      const res = await request(app)
        .get('/api/v1/vehicles?status=MAINTENANCE')
        .set(authHeader(token))

      expect(res.status).toBe(200)
      res.body.data.forEach((v: any) => expect(v.status).toBe('MAINTENANCE'))
    })
  })

  describe('POST /api/v1/vehicles', () => {
    it('creates a vehicle with valid payload', async () => {
      const res = await request(app)
        .post('/api/v1/vehicles')
        .set(authHeader(token))
        .send({
          make:         'Honda',
          model:        'Civic',
          year:         2023,
          licensePlate: `TEST-${Date.now()}`,
          category:     'COMPACT',
          dailyRate:    400,
          pickupLocations: ['Casablanca Airport', 'Casablanca Downtown'],
          allowDifferentDropoff: true,
          dropoffLocations: ['Rabat Downtown'],
        })

      expect(res.status).toBe(201)
      expect(res.body.data.make).toBe('Honda')
      expect(res.body.data.model).toBe('Civic')
      expect(res.body.data.pickupLocations).toEqual(['Casablanca Airport', 'Casablanca Downtown'])
      expect(res.body.data.allowDifferentDropoff).toBe(true)
      expect(res.body.data.dropoffLocations).toEqual(['Rabat Downtown'])
    })

    it('creates a vehicle without a daily rate and defaults it to zero', async () => {
      const res = await request(app)
        .post('/api/v1/vehicles')
        .set(authHeader(token))
        .send({
          make: 'Nissan',
          model: 'Micra',
          year: 2024,
          licensePlate: `ZERO-${Date.now()}`,
          category: 'ECONOMY',
        })

      expect(res.status).toBe(201)
      expect(res.body.data.dailyRate).toBe(0)
    })

    it('returns 400 for missing required fields', async () => {
      const res = await request(app)
        .post('/api/v1/vehicles')
        .set(authHeader(token))
        .send({ make: 'Honda' })

      expect(res.status).toBe(400)
    })
  })

  describe('GET /api/v1/vehicles/:id', () => {
    it('returns a single vehicle', async () => {
      const vehicle = await createVehicle(companyId, { make: 'BMW', model: 'X5' })

      const res = await request(app)
        .get(`/api/v1/vehicles/${vehicle.id}`)
        .set(authHeader(token))

      expect(res.status).toBe(200)
      expect(res.body.data.id).toBe(vehicle.id)
      expect(res.body.data.make).toBe('BMW')
    })

    it('returns 404 for unknown vehicle', async () => {
      const res = await request(app)
        .get('/api/v1/vehicles/clzunknownidzzzzzzzzzzz')
        .set(authHeader(token))

      expect(res.status).toBe(404)
    })
  })

  describe('PATCH /api/v1/vehicles/:id', () => {
    it('updates vehicle notes', async () => {
      const vehicle = await createVehicle(companyId)

      const res = await request(app)
        .patch(`/api/v1/vehicles/${vehicle.id}`)
        .set(authHeader(token))
        .send({ notes: 'Updated via integration test' })

      expect(res.status).toBe(200)
      expect(res.body.data.notes).toBe('Updated via integration test')
    })

    it('updates pickup and drop-off settings', async () => {
      const vehicle = await createVehicle(companyId)

      const res = await request(app)
        .patch(`/api/v1/vehicles/${vehicle.id}`)
        .set(authHeader(token))
        .send({
          pickupLocations: ['Casablanca Airport'],
          allowDifferentDropoff: true,
          dropoffLocations: ['Rabat Downtown', 'Marrakech Center'],
        })

      expect(res.status).toBe(200)
      expect(res.body.data.pickupLocations).toEqual(['Casablanca Airport'])
      expect(res.body.data.allowDifferentDropoff).toBe(true)
      expect(res.body.data.dropoffLocations).toEqual(['Rabat Downtown', 'Marrakech Center'])
    })

    it('sets isPublished=false when status=MAINTENANCE', async () => {
      const vehicle = await createVehicle(companyId)

      const res = await request(app)
        .patch(`/api/v1/vehicles/${vehicle.id}`)
        .set(authHeader(token))
        .send({ status: 'MAINTENANCE' })

      expect(res.status).toBe(200)
      expect(res.body.data.status).toBe('MAINTENANCE')
      expect(res.body.data.isPublished).toBe(false)
    })
  })

  describe('GET /api/v1/vehicles/:id/availability', () => {
    it('reports vehicle available for future dates', async () => {
      const vehicle = await createVehicle(companyId)
      const start = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]
      const end   = new Date(Date.now() + 14 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]

      const res = await request(app)
        .get(`/api/v1/vehicles/${vehicle.id}/availability?startDate=${start}&endDate=${end}`)
        .set(authHeader(token))

      expect(res.status).toBe(200)
      expect(res.body.data.available).toBe(true)
    })
  })

  describe('GET /api/v1/vehicles/:id/maintenance — tenant isolation (VF-03)', () => {
    it('returns 401 without auth', async () => {
      const vehicle = await createVehicle(companyId)
      const res = await request(app).get(`/api/v1/vehicles/${vehicle.id}/maintenance`)
      expect(res.status).toBe(401)
    })

    it('returns maintenance logs for own company vehicle', async () => {
      const vehicle = await createVehicle(companyId)
      await prisma.maintenanceLog.create({
        data: {
          vehicleId:   vehicle.id,
          type:        'OIL_CHANGE',
          description: 'Routine oil change',
          cost:        250,
          performedAt: new Date(),
        } as any,
      })

      const res = await request(app)
        .get(`/api/v1/vehicles/${vehicle.id}/maintenance`)
        .set(authHeader(token))

      expect(res.status).toBe(200)
      expect(Array.isArray(res.body.data)).toBe(true)
      expect(res.body.data.length).toBeGreaterThanOrEqual(1)
    })

    it('returns 404 when accessing maintenance logs for a vehicle belonging to another company', async () => {
      const { company: otherCompany } = await createCompanyWithEmployee({ role: 'OWNER' })
      const foreignVehicle = await createVehicle(otherCompany.id, { make: 'BMW', model: 'X5' })

      const res = await request(app)
        .get(`/api/v1/vehicles/${foreignVehicle.id}/maintenance`)
        .set(authHeader(token))

      expect(res.status).toBe(404)
    })

    it('does not leak maintenance logs across companies even when vehicle id is known', async () => {
      const { company: otherCompany } = await createCompanyWithEmployee({ role: 'OWNER' })
      const foreignVehicle = await createVehicle(otherCompany.id)
      await prisma.maintenanceLog.create({
        data: {
          vehicleId:   foreignVehicle.id,
          type:        'TIRE_ROTATION',
          description: 'Other company private data',
          cost:        100,
          performedAt: new Date(),
        } as any,
      })

      const res = await request(app)
        .get(`/api/v1/vehicles/${foreignVehicle.id}/maintenance`)
        .set(authHeader(token))

      expect(res.status).toBe(404)
    })
  })

  describe('Vehicle pricing management', () => {
    it('returns a default pricing configuration for a vehicle', async () => {
      const vehicle = await createVehicle(companyId, { dailyRate: 6250 })

      const res = await request(app)
        .get(`/api/v1/vehicles/${vehicle.id}/pricing`)
        .set(authHeader(token))

      expect(res.status).toBe(200)
      expect(res.body.data.configuration.baseDailyRate).toBe(6250)
      expect(res.body.data.configuration.pricingMode).toBe('MANUAL')
      expect(Array.isArray(res.body.data.preview.next14Days)).toBe(true)
      expect(res.body.data.preview.next14Days.length).toBe(14)
    })

    it('updates vehicle pricing configuration and syncs the vehicle daily rate', async () => {
      const vehicle = await createVehicle(companyId, { dailyRate: 5000 })

      const res = await request(app)
        .put(`/api/v1/vehicles/${vehicle.id}/pricing`)
        .set(authHeader(token))
        .send({
          pricingMode: 'AUTOMATIC',
          baseDailyRate: 6400,
          weeklyRate: 39900,
          weekendRate: 7200,
          holidayRate: null,
          monthlyRate: 118000,
          longTermDailyRate: 5600,
          minimumDailyRate: 5900,
          maximumDailyRate: 8600,
          maxDailyPriceMovementPct: 12,
          automaticPricingEnabled: true,
          approvalRequired: true,
          note: 'Summer setup',
        })

      expect(res.status).toBe(200)
      expect(res.body.data.configuration.pricingMode).toBe('AUTOMATIC')
      expect(res.body.data.configuration.baseDailyRate).toBe(6400)
      expect(res.body.data.history[0].note).toBe('Summer setup')

      const updatedVehicle = await prisma.vehicle.findUniqueOrThrow({ where: { id: vehicle.id } })
      expect(updatedVehicle.dailyRate).toBe(6400)
    })

    it('creates, updates, and deletes pricing rules', async () => {
      const vehicle = await createVehicle(companyId, { dailyRate: 5400 })

      const createRes = await request(app)
        .post(`/api/v1/vehicles/${vehicle.id}/pricing/rules`)
        .set(authHeader(token))
        .send({
          name: 'Summer high season',
          ruleType: 'SEASONAL',
          startDate: '2026-07-01',
          endDate: '2026-08-31',
          dailyRate: 7800,
          weeklyRate: 46900,
          weekendRate: null,
          monthlyRate: null,
          minDailyRate: null,
          maxDailyRate: null,
          automaticAdjustmentPct: null,
          priceAdjustment: null,
          isActive: true,
          sortOrder: 30,
        })

      expect(createRes.status).toBe(201)
      expect(createRes.body.data.rules.length).toBe(1)
      const createdRule = createRes.body.data.rules[0]

      const updateRes = await request(app)
        .patch(`/api/v1/vehicles/${vehicle.id}/pricing/rules/${createdRule.id}`)
        .set(authHeader(token))
        .send({
          dailyRate: 8100,
          weeklyRate: 48900,
          sortOrder: 40,
        })

      expect(updateRes.status).toBe(200)
      const updatedRule = updateRes.body.data.rules.find((rule: any) => rule.id === createdRule.id)
      expect(updatedRule.dailyRate).toBe(8100)
      expect(updatedRule.weeklyRate).toBe(48900)

      const deleteRes = await request(app)
        .delete(`/api/v1/vehicles/${vehicle.id}/pricing/rules/${createdRule.id}`)
        .set(authHeader(token))

      expect(deleteRes.status).toBe(200)
      expect(deleteRes.body.data.rules).toHaveLength(0)
      expect(deleteRes.body.data.history.length).toBeGreaterThanOrEqual(1)
    })
  })
})
