import { describe, it, expect, beforeAll, afterAll, afterEach, vi } from 'vitest'
import { renderHook, waitFor, act } from '@testing-library/react'
import { http, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import React from 'react'
import { useProductTypes } from '../../../features/product-types/hooks/useProductTypes'
import { useCreateProductType } from '../../../features/product-types/hooks/useCreateProductType'
import { useUpdateProductType } from '../../../features/product-types/hooks/useUpdateProductType'
import { useDeactivateProductType } from '../../../features/product-types/hooks/useDeactivateProductType'
import type { ProductTypeListItem, PagedResult } from '../../../features/product-types/types'

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

const mockItem: ProductTypeListItem = {
  id: 1,
  nombre: 'Avisos',
  hasDuration: false,
  requiresText: false,
  requiresCategory: false,
  isBundle: false,
  allowImages: false,
  isActive: true,
}

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

const server = setupServer()

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

function makeWrapper() {
  const qc = new QueryClient({
    defaultOptions: { queries: { retry: false }, mutations: { retry: false } },
  })
  return ({ children }: { children: React.ReactNode }) =>
    React.createElement(QueryClientProvider, { client: qc }, children)
}

describe('useProductTypes', () => {
  it('returns paged data on success', async () => {
    server.use(
      http.get(`${API_URL}/api/v1/product-types`, () => HttpResponse.json(mockPaged)),
    )
    const { result } = renderHook(() => useProductTypes(), { wrapper: makeWrapper() })
    await waitFor(() => expect(result.current.isSuccess).toBe(true))
    expect(result.current.data).toEqual(mockPaged)
  })

  it('returns error state on failure', async () => {
    server.use(
      http.get(`${API_URL}/api/v1/product-types`, () =>
        HttpResponse.json({ error: 'server_error' }, { status: 500 }),
      ),
    )
    const { result } = renderHook(() => useProductTypes(), { wrapper: makeWrapper() })
    await waitFor(() => expect(result.current.isError).toBe(true))
  })
})

describe('useCreateProductType', () => {
  it('calls create and invalidates product-types queries on success', async () => {
    server.use(
      http.post(`${API_URL}/api/v1/admin/product-types`, () =>
        HttpResponse.json(mockItem, { status: 201 }),
      ),
    )
    const qc = new QueryClient({
      defaultOptions: { queries: { retry: false }, mutations: { retry: false } },
    })
    const invalidateSpy = vi.spyOn(qc, 'invalidateQueries')
    const wrapper = ({ children }: { children: React.ReactNode }) =>
      React.createElement(QueryClientProvider, { client: qc }, children)

    const { result } = renderHook(() => useCreateProductType(), { wrapper })
    await act(async () => {
      result.current.mutate({
        nombre: 'Nuevo',
        hasDuration: false,
        requiresText: false,
        requiresCategory: false,
        isBundle: false,
        allowImages: false,
      })
    })
    await waitFor(() => expect(result.current.isSuccess).toBe(true))
    expect(invalidateSpy).toHaveBeenCalledWith({ queryKey: ['product-types'] })
  })
})

describe('useUpdateProductType', () => {
  it('calls update and invalidates product-types queries on success', async () => {
    server.use(
      http.put(`${API_URL}/api/v1/admin/product-types/1`, () =>
        HttpResponse.json(mockItem),
      ),
    )
    const qc = new QueryClient({
      defaultOptions: { queries: { retry: false }, mutations: { retry: false } },
    })
    const invalidateSpy = vi.spyOn(qc, 'invalidateQueries')
    const wrapper = ({ children }: { children: React.ReactNode }) =>
      React.createElement(QueryClientProvider, { client: qc }, children)

    const { result } = renderHook(() => useUpdateProductType(), { wrapper })
    await act(async () => {
      result.current.mutate({
        id: 1,
        data: { nombre: 'Modificado', hasDuration: false, requiresText: false, requiresCategory: false, isBundle: false, allowImages: false },
      })
    })
    await waitFor(() => expect(result.current.isSuccess).toBe(true))
    expect(invalidateSpy).toHaveBeenCalledWith({ queryKey: ['product-types'] })
  })
})

describe('useDeactivateProductType', () => {
  it('calls deactivate and invalidates product-types queries on success', async () => {
    server.use(
      http.delete(`${API_URL}/api/v1/admin/product-types/1`, () =>
        new HttpResponse(null, { status: 204 }),
      ),
    )
    const qc = new QueryClient({
      defaultOptions: { queries: { retry: false }, mutations: { retry: false } },
    })
    const invalidateSpy = vi.spyOn(qc, 'invalidateQueries')
    const wrapper = ({ children }: { children: React.ReactNode }) =>
      React.createElement(QueryClientProvider, { client: qc }, children)

    const { result } = renderHook(() => useDeactivateProductType(), { wrapper })
    await act(async () => {
      result.current.mutate(1)
    })
    await waitFor(() => expect(result.current.isSuccess).toBe(true))
    expect(invalidateSpy).toHaveBeenCalledWith({ queryKey: ['product-types'] })
  })
})
