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

const app = createApp()

const future = (days: number) =>
  new Date(Date.now() + days * 24 * 60 * 60 * 1000).toISOString()

describe('Reservations API', () => {
  let companyId: string
  let token: string
  let vehicleId: string
  let customerId: string

  beforeAll(async () => {
    const { company, employee } = await createCompanyWithEmployee({ role: 'OWNER' })
    companyId  = company.id
    token      = signEmployeeToken(employee.id, companyId, 'OWNER')
    const v    = await createVehicle(companyId)
    vehicleId  = v.id
    const c    = await createCustomer(companyId)
    customerId = c.id
  })

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

    it('returns paginated list', async () => {
      const res = await request(app)
        .get('/api/v1/reservations')
        .set(authHeader(token))

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

  describe('POST /api/v1/reservations', () => {
    it('creates a reservation with valid payload', async () => {
      const res = await request(app)
        .post('/api/v1/reservations')
        .set(authHeader(token))
        .send({
          vehicleId,
          customerId,
          startDate: future(10),
          endDate:   future(15),
        })

      expect(res.status).toBe(201)
      expect(res.body.data.vehicleId).toBe(vehicleId)
      expect(res.body.data.customerId).toBe(customerId)
      expect(res.body.data.status).toBe('DRAFT')
    })

    it('returns 400 for missing vehicleId', async () => {
      const res = await request(app)
        .post('/api/v1/reservations')
        .set(authHeader(token))
        .send({
          customerId,
          startDate: future(10),
          endDate:   future(15),
        })

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

    it('returns 409 when vehicle is not available for requested dates', async () => {
      // Create a reservation blocking the vehicle
      const createRes = await request(app)
        .post('/api/v1/reservations')
        .set(authHeader(token))
        .send({ vehicleId, customerId, startDate: future(20), endDate: future(25) })
        .expect(201)

      await request(app)
        .post(`/api/v1/reservations/${createRes.body.data.id}/confirm`)
        .set(authHeader(token))
        .expect(200)

      const res = await request(app)
        .post('/api/v1/reservations')
        .set(authHeader(token))
        .send({ vehicleId, customerId, startDate: future(21), endDate: future(24) })

      // Overlapping dates should conflict
      expect([409, 422]).toContain(res.status)
    })
  })

  describe('Reservation state machine', () => {
    let reservationId: string

    beforeEach(async () => {
      const v = await createVehicle(companyId)
      const res = await request(app)
        .post('/api/v1/reservations')
        .set(authHeader(token))
        .send({ vehicleId: v.id, customerId, startDate: future(30), endDate: future(35) })
      expect(res.status).toBe(201)
      reservationId = res.body.data.id
    })

    it('DRAFT → CONFIRMED via POST /:id/confirm', async () => {
      const res = await request(app)
        .post(`/api/v1/reservations/${reservationId}/confirm`)
        .set(authHeader(token))

      expect(res.status).toBe(200)
      expect(res.body.data.status).toBe('CONFIRMED')
    })

    it('CONFIRMED → ACTIVE via POST /:id/checkin', async () => {
      await request(app)
        .post(`/api/v1/reservations/${reservationId}/confirm`)
        .set(authHeader(token))
        .expect(200)

      const res = await request(app)
        .post(`/api/v1/reservations/${reservationId}/checkin`)
        .set(authHeader(token))
        .send({ fuelLevel: 'FULL' })

      expect(res.status).toBe(200)
      expect(res.body.data.status).toBe('ACTIVE')
    })
  })
})
