import { describe, it, expect, beforeAll, afterAll, afterEach } from 'vitest'
import { http, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
import { listProducts } from '../../../features/products/api/listProducts'
import { getProductById } from '../../../features/products/api/getProductById'
import { createProduct } from '../../../features/products/api/createProduct'
import { updateProduct } from '../../../features/products/api/updateProduct'
import { deactivateProduct } from '../../../features/products/api/deactivateProduct'
import type { ProductListItem, ProductDetail, PagedResult } from '../../../features/products/types'

const API_URL = 'http://localhost:5000'

const mockListItem: ProductListItem = {
  id: 1,
  nombre: 'Clasificado Estándar',
  medioId: 1,
  productTypeId: 2,
  rubroId: null,
  basePrice: 100.50,
  priceDurationDays: null,
  isActive: true,
}

const mockDetail: ProductDetail = {
  id: 1,
  nombre: 'Clasificado Estándar',
  medioId: 1,
  productTypeId: 2,
  rubroId: null,
  basePrice: 100.50,
  priceDurationDays: null,
  isActive: true,
  fechaCreacion: '2026-04-19T00:00:00Z',
  fechaModificacion: null,
}

const mockPaged: PagedResult<ProductListItem> = {
  items: [mockListItem],
  page: 1,
  pageSize: 20,
  total: 1,
}

const server = setupServer()

beforeAll(() => server.listen({ onUnhandledRequest: 'error' }))
afterEach(() => server.resetHandlers())
afterAll(() => server.close())

describe('listProducts', () => {
  it('calls GET /api/v1/products and returns paged result', async () => {
    server.use(
      http.get(`${API_URL}/api/v1/products`, () => HttpResponse.json(mockPaged)),
    )
    const result = await listProducts()
    expect(result).toEqual(mockPaged)
  })

  it('passes query params when provided', async () => {
    let capturedUrl = ''
    server.use(
      http.get(`${API_URL}/api/v1/products`, ({ request }) => {
        capturedUrl = request.url
        return HttpResponse.json(mockPaged)
      }),
    )
    await listProducts({ page: 2, pageSize: 10, activo: true, medioId: 5 })
    expect(capturedUrl).toContain('page=2')
    expect(capturedUrl).toContain('pageSize=10')
    expect(capturedUrl).toContain('medioId=5')
  })
})

describe('getProductById', () => {
  it('calls GET /api/v1/products/:id and returns detail', async () => {
    server.use(
      http.get(`${API_URL}/api/v1/products/1`, () => HttpResponse.json(mockDetail)),
    )
    const result = await getProductById(1)
    expect(result).toEqual(mockDetail)
  })
})

describe('createProduct', () => {
  it('calls POST /api/v1/admin/products with payload', async () => {
    let capturedBody: unknown = null
    server.use(
      http.post(`${API_URL}/api/v1/admin/products`, async ({ request }) => {
        capturedBody = await request.json()
        return HttpResponse.json(mockDetail, { status: 201 })
      }),
    )
    const req = {
      nombre: 'Clasificado Estándar',
      medioId: 1,
      productTypeId: 2,
      basePrice: 100.50,
    }
    await createProduct(req)
    expect(capturedBody).toEqual(req)
  })
})

describe('updateProduct', () => {
  it('calls PUT /api/v1/admin/products/:id with payload', async () => {
    let capturedBody: unknown = null
    server.use(
      http.put(`${API_URL}/api/v1/admin/products/1`, async ({ request }) => {
        capturedBody = await request.json()
        return HttpResponse.json(mockDetail)
      }),
    )
    const req = { nombre: 'Modificado', basePrice: 200 }
    await updateProduct(1, req)
    expect(capturedBody).toEqual(req)
  })
})

describe('deactivateProduct', () => {
  it('calls DELETE /api/v1/admin/products/:id', async () => {
    let called = false
    server.use(
      http.delete(`${API_URL}/api/v1/admin/products/1`, () => {
        called = true
        return new HttpResponse(null, { status: 204 })
      }),
    )
    await deactivateProduct(1)
    expect(called).toBe(true)
  })
})
