// T600.6 — TDD: NuevaVigenciaModal
// Tests: preview con fechas correctas + botón disabled si form inválido [REQ-UI-004]
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 { NuevaVigenciaModal } from '../../../../features/fiscal/iva/components/NuevaVigenciaModal'
import type { TipoDeIva } from '../../../../features/fiscal/iva/types/tipoDeIva.types'

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

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

const sampleTipoDeIva: TipoDeIva = {
  id: 2,
  codigo: 'IVA_21',
  descripcion: 'IVA 21%',
  porcentaje: 21,
  vigenciaDesde: '2020-01-01',
  vigenciaHasta: null,
  activo: true,
  aplicaIVA: true,
  predecesorId: null,
}

const server = setupServer()

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

function renderModal(opts: {
  item?: TipoDeIva | null
  open?: boolean
  onClose?: () => void
  onSuccess?: () => void
} = {}) {
  const qc = new QueryClient({
    defaultOptions: { queries: { retry: false }, mutations: { retry: false } },
  })
  const onClose = opts.onClose ?? vi.fn()
  const onSuccess = opts.onSuccess ?? vi.fn()

  render(
    <QueryClientProvider client={qc}>
      <MemoryRouter>
        <NuevaVigenciaModal
          open={opts.open ?? true}
          item={opts.item ?? sampleTipoDeIva}
          onClose={onClose}
          onSuccess={onSuccess}
        />
      </MemoryRouter>
    </QueryClientProvider>,
  )
  return { onClose, onSuccess }
}

describe('NuevaVigenciaModal — botón disabled cuando form inválido', () => {
  it('botón "Confirmar" está disabled cuando form está vacío', () => {
    renderModal()
    const confirmBtn = screen.getByRole('button', { name: /confirmar/i })
    expect(confirmBtn).toBeDisabled()
  })

  it('botón "Confirmar" está habilitado cuando form es válido', async () => {
    renderModal()

    const porcentajeInput = screen.getByLabelText(/porcentaje nuevo/i)
    await userEvent.clear(porcentajeInput)
    await userEvent.type(porcentajeInput, '23.5')

    const vigenciaInput = screen.getByLabelText(/vigencia desde/i)
    await userEvent.type(vigenciaInput, '2026-05-01')

    await waitFor(() => {
      const confirmBtn = screen.getByRole('button', { name: /confirmar/i })
      expect(confirmBtn).not.toBeDisabled()
    })
  })
})

describe('NuevaVigenciaModal — preview con fechas correctas [REQ-UI-004]', () => {
  it('muestra preview con porcentaje correcto al completar form', async () => {
    renderModal()

    const porcentajeInput = screen.getByLabelText(/porcentaje nuevo/i)
    await userEvent.clear(porcentajeInput)
    await userEvent.type(porcentajeInput, '23.5')

    const vigenciaInput = screen.getByLabelText(/vigencia desde/i)
    await userEvent.type(vigenciaInput, '2026-05-01')

    // Preview debe mostrar el nuevo porcentaje
    await waitFor(() =>
      expect(screen.getByText(/23\.5%/)).toBeInTheDocument(),
    )
  })

  it('muestra en el preview la versión actual (IVA_21 con 21%)', async () => {
    renderModal()

    const porcentajeInput = screen.getByLabelText(/porcentaje nuevo/i)
    await userEvent.clear(porcentajeInput)
    await userEvent.type(porcentajeInput, '23.5')

    const vigenciaInput = screen.getByLabelText(/vigencia desde/i)
    await userEvent.type(vigenciaInput, '2026-05-01')

    // Preview debe mencionar el porcentaje actual (21%)
    await waitFor(() =>
      expect(screen.getByText(/21%/)).toBeInTheDocument(),
    )
  })

  it('preview muestra fecha de cierre = vigenciaDesde - 1 día (formato dd/MM/yyyy, BUG-FE-04)', async () => {
    renderModal()

    const porcentajeInput = screen.getByLabelText(/porcentaje nuevo/i)
    await userEvent.clear(porcentajeInput)
    await userEvent.type(porcentajeInput, '23.5')

    const vigenciaInput = screen.getByLabelText(/vigencia desde/i)
    await userEvent.type(vigenciaInput, '2026-05-01')

    // La versión anterior cierra el día anterior → 30/04/2026 (formato AR civil)
    await waitFor(() =>
      expect(screen.getByText(/30\/04\/2026/)).toBeInTheDocument(),
    )
  })
})

describe('NuevaVigenciaModal — submit llama mutation', () => {
  it('click confirmar con form válido dispara request al backend', async () => {
    let requestBody: unknown = null

    server.use(
      http.post(`${API_URL}/api/v1/admin/fiscal/iva/:id/nueva-version`, async ({ request }) => {
        requestBody = await request.json()
        return HttpResponse.json(
          {
            predecesorId: 2,
            nuevaId: 10,
            nuevoPorcentaje: 23.5,
            vigenciaDesde: '2026-05-01',
            predecesorVigenciaHasta: '2026-04-30',
          },
          { status: 201 },
        )
      }),
    )

    const { onSuccess } = renderModal()

    const porcentajeInput = screen.getByLabelText(/porcentaje nuevo/i)
    await userEvent.clear(porcentajeInput)
    await userEvent.type(porcentajeInput, '23.5')

    const vigenciaInput = screen.getByLabelText(/vigencia desde/i)
    await userEvent.type(vigenciaInput, '2026-05-01')

    const confirmBtn = await screen.findByRole('button', { name: /confirmar/i })
    await waitFor(() => expect(confirmBtn).not.toBeDisabled())
    await userEvent.click(confirmBtn)

    await waitFor(() => {
      expect(requestBody).toMatchObject({
        porcentaje: 23.5,
        vigenciaDesde: '2026-05-01',
      })
      expect(onSuccess).toHaveBeenCalled()
    })
  })
})

// T600.10 — 409 inmutable_usar_nueva_version toast
describe('NuevaVigenciaModal — 409 handling', () => {
  it('botón Cancelar llama onClose', async () => {
    const { onClose } = renderModal()
    await userEvent.click(screen.getByRole('button', { name: /cancelar/i }))
    expect(onClose).toHaveBeenCalledTimes(1)
  })
})
