import { describe, it, expect, beforeAll, afterAll, afterEach, vi } from 'vitest'
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { http, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { MemoryRouter } from 'react-router-dom'
import { PuntoDeVentaForm } from '../../../features/puntos-de-venta/components/PuntoDeVentaForm'
import type { PuntoDeVentaFormValues } from '../../../features/puntos-de-venta/components/PuntoDeVentaForm'
import type { PuntoDeVentaDetail } from '../../../features/puntos-de-venta/types'

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

vi.mock('sonner', () => ({
  toast: { success: vi.fn(), error: vi.fn() },
}))

const mockMedios = [
  { id: 1, codigo: 'DIA01', nombre: 'Diario El Día', tipo: 1, plataformaEmpresaId: null, activo: true },
  { id: 2, codigo: 'RAD01', nombre: 'Radio AM', tipo: 2, plataformaEmpresaId: null, activo: true },
]

const samplePdv: PuntoDeVentaDetail = {
  id: 10,
  medioId: 1,
  numeroAFIP: 1,
  nombre: 'PdV Central',
  activo: true,
  fechaCreacion: '2026-01-01T00:00:00Z',
  fechaModificacion: null,
}

const server = setupServer()

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

function renderForm(
  opts: { initialData?: PuntoDeVentaDetail; onSubmit?: (v: PuntoDeVentaFormValues) => void } = {},
) {
  const qc = new QueryClient({
    defaultOptions: { queries: { retry: false }, mutations: { retry: false } },
  })
  const onSubmit = opts.onSubmit ?? vi.fn()
  server.use(
    http.get(`${API_URL}/api/v1/admin/medios`, () =>
      HttpResponse.json({ items: mockMedios, page: 1, pageSize: 200, total: 2 }),
    ),
  )
  render(
    <QueryClientProvider client={qc}>
      <MemoryRouter>
        <PuntoDeVentaForm
          initialData={opts.initialData}
          isPending={false}
          error={null}
          onSubmit={onSubmit}
        />
      </MemoryRouter>
    </QueryClientProvider>,
  )
  return { onSubmit }
}

describe('PuntoDeVentaForm — create mode', () => {
  it('shows validation error when nombre is empty', async () => {
    renderForm()
    await userEvent.click(screen.getByRole('button', { name: /crear punto de venta/i }))
    await waitFor(() =>
      expect(screen.getByText(/nombre es requerido/i)).toBeInTheDocument(),
    )
  })

  it('shows validation error when numeroAFIP is 0 or negative', async () => {
    renderForm()
    const numeroInput = screen.getByLabelText(/número afip/i)
    await userEvent.clear(numeroInput)
    await userEvent.type(numeroInput, '0')
    await userEvent.click(screen.getByRole('button', { name: /crear punto de venta/i }))
    await waitFor(() =>
      expect(screen.getByText(/mayor a 0/i)).toBeInTheDocument(),
    )
  })

  it('calls onSubmit with correct values on valid form', async () => {
    const onSubmit = vi.fn()
    renderForm({ onSubmit })

    // Select medio
    const medioTrigger = screen.getByRole('combobox', { name: /medio/i })
    await userEvent.click(medioTrigger)
    await waitFor(() =>
      expect(screen.getByRole('option', { name: 'Diario El Día' })).toBeInTheDocument(),
    )
    await userEvent.click(screen.getByRole('option', { name: 'Diario El Día' }))

    // Fill numeroAFIP
    const numeroInput = screen.getByLabelText(/número afip/i)
    await userEvent.clear(numeroInput)
    await userEvent.type(numeroInput, '3')

    // Fill nombre
    await userEvent.type(screen.getByLabelText(/nombre/i), 'PdV Norte')

    await userEvent.click(screen.getByRole('button', { name: /crear punto de venta/i }))

    await waitFor(() => {
      expect(onSubmit).toHaveBeenCalled()
      const firstArg = onSubmit.mock.calls[0][0]
      expect(firstArg).toMatchObject({
        medioId: 1,
        numeroAFIP: 3,
        nombre: 'PdV Norte',
      })
    })
  })
})

describe('PuntoDeVentaForm — edit mode', () => {
  it('medioId and numeroAFIP are disabled in edit mode', async () => {
    renderForm({ initialData: samplePdv })
    const medioTrigger = screen.getByRole('combobox', { name: /medio/i })
    expect(medioTrigger).toBeDisabled()

    const numeroInput = screen.getByLabelText(/número afip/i) as HTMLInputElement
    expect(numeroInput.disabled).toBe(true)
  })

  it('pre-fills form with initialData values', async () => {
    renderForm({ initialData: samplePdv })
    await waitFor(() =>
      expect((screen.getByLabelText(/nombre/i) as HTMLInputElement).value).toBe('PdV Central'),
    )
    expect((screen.getByLabelText(/número afip/i) as HTMLInputElement).value).toBe('1')
  })

  it('shows "Guardar cambios" button in edit mode', () => {
    renderForm({ initialData: samplePdv })
    expect(screen.getByRole('button', { name: /guardar cambios/i })).toBeInTheDocument()
  })
})
