import { describe, it, expect, beforeAll, afterAll, afterEach } 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 { RolPermisosEditor } from '../../../features/permisos/components/RolPermisosEditor'

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

const catalogoPermisos = [
  { id: 1, codigo: 'ventas:contado:crear', nombre: 'Crear venta contado', descripcion: 'Permite crear una venta al contado', modulo: 'ventas' },
  { id: 2, codigo: 'ventas:contado:anular', nombre: 'Anular venta contado', descripcion: 'Permite anular una venta al contado', modulo: 'ventas' },
  { id: 3, codigo: 'reportes:ventas:ver', nombre: 'Ver reporte ventas', descripcion: 'Permite ver el reporte de ventas', modulo: 'reportes' },
  { id: 4, codigo: 'admin:usuarios:gestionar', nombre: 'Gestionar usuarios', descripcion: 'Permite crear y editar usuarios', modulo: 'admin' },
]

const rolPermisos = [
  catalogoPermisos[0]!, // ventas:contado:crear
  catalogoPermisos[2]!, // reportes:ventas:ver
]

const server = setupServer()

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

function renderEditor(rolCodigo = 'cajero') {
  const qc = new QueryClient({
    defaultOptions: { queries: { retry: false }, mutations: { retry: false } },
  })
  return render(
    <QueryClientProvider client={qc}>
      <MemoryRouter>
        <RolPermisosEditor rolCodigo={rolCodigo} />
      </MemoryRouter>
    </QueryClientProvider>,
  )
}

describe('RolPermisosEditor', () => {
  it('renders without crash and shows permission checkboxes grouped by module', async () => {
    server.use(
      http.get(`${API_URL}/api/v1/permisos`, () => HttpResponse.json(catalogoPermisos)),
      http.get(`${API_URL}/api/v1/roles/cajero/permisos`, () => HttpResponse.json(rolPermisos)),
    )

    renderEditor()

    // Loading state should appear initially
    expect(screen.getByText(/cargando permisos/i)).toBeInTheDocument()

    // After fetch resolves, show groups
    await waitFor(() => expect(screen.getByText('ventas')).toBeInTheDocument())

    expect(screen.getByText('reportes')).toBeInTheDocument()
    expect(screen.getByText('admin')).toBeInTheDocument()

    // Shows permission names
    expect(screen.getByLabelText('Crear venta contado')).toBeInTheDocument()
    expect(screen.getByLabelText('Anular venta contado')).toBeInTheDocument()
    expect(screen.getByLabelText('Ver reporte ventas')).toBeInTheDocument()
    expect(screen.getByLabelText('Gestionar usuarios')).toBeInTheDocument()
  })

  it('prefills checkboxes for already-assigned permissions', async () => {
    server.use(
      http.get(`${API_URL}/api/v1/permisos`, () => HttpResponse.json(catalogoPermisos)),
      http.get(`${API_URL}/api/v1/roles/cajero/permisos`, () => HttpResponse.json(rolPermisos)),
    )

    renderEditor()

    await waitFor(() => expect(screen.getByLabelText('Crear venta contado')).toBeInTheDocument())

    const crearCheckbox = screen.getByLabelText('Crear venta contado') as HTMLInputElement
    const anularCheckbox = screen.getByLabelText('Anular venta contado') as HTMLInputElement
    const reporteCheckbox = screen.getByLabelText('Ver reporte ventas') as HTMLInputElement
    const adminCheckbox = screen.getByLabelText('Gestionar usuarios') as HTMLInputElement

    // cajero has ventas:contado:crear and reportes:ventas:ver assigned
    expect(crearCheckbox.checked).toBe(true)
    expect(reporteCheckbox.checked).toBe(true)
    // not assigned
    expect(anularCheckbox.checked).toBe(false)
    expect(adminCheckbox.checked).toBe(false)
  })

  it('toggles a checkbox on click', async () => {
    server.use(
      http.get(`${API_URL}/api/v1/permisos`, () => HttpResponse.json(catalogoPermisos)),
      http.get(`${API_URL}/api/v1/roles/cajero/permisos`, () => HttpResponse.json(rolPermisos)),
    )

    const u = userEvent.setup()
    renderEditor()

    await waitFor(() => expect(screen.getByLabelText('Anular venta contado')).toBeInTheDocument())

    const anularCheckbox = screen.getByLabelText('Anular venta contado') as HTMLInputElement
    expect(anularCheckbox.checked).toBe(false)

    // Toggle on
    await u.click(anularCheckbox)
    expect(anularCheckbox.checked).toBe(true)

    // Toggle off
    await u.click(anularCheckbox)
    expect(anularCheckbox.checked).toBe(false)
  })

  it('shows success alert after saving permissions', async () => {
    server.use(
      http.get(`${API_URL}/api/v1/permisos`, () => HttpResponse.json(catalogoPermisos)),
      http.get(`${API_URL}/api/v1/roles/cajero/permisos`, () => HttpResponse.json(rolPermisos)),
      http.put(`${API_URL}/api/v1/roles/cajero/permisos`, () => new HttpResponse(null, { status: 200 })),
    )

    const u = userEvent.setup()
    renderEditor()

    await waitFor(() => expect(screen.getByText('Guardar cambios')).toBeInTheDocument())

    await u.click(screen.getByText('Guardar cambios'))

    await waitFor(() =>
      expect(screen.getByRole('status')).toHaveTextContent(/guardados correctamente/i),
    )
  })

  it('shows 400 error message when admin would be left without permissions', async () => {
    server.use(
      http.get(`${API_URL}/api/v1/permisos`, () => HttpResponse.json(catalogoPermisos)),
      http.get(`${API_URL}/api/v1/roles/admin/permisos`, () => HttpResponse.json(catalogoPermisos)),
      http.put(`${API_URL}/api/v1/roles/admin/permisos`, () =>
        HttpResponse.json({ message: 'El rol admin no puede quedar sin permisos' }, { status: 400 }),
      ),
    )

    const u = userEvent.setup()
    renderEditor('admin')

    await waitFor(() => expect(screen.getByText('Guardar cambios')).toBeInTheDocument())

    await u.click(screen.getByText('Guardar cambios'))

    await waitFor(() =>
      expect(screen.getByRole('alert')).toHaveTextContent(/admin.*sin permisos/i),
    )
  })
})
