import { describe, it, expect, beforeAll, afterAll, afterEach } from 'vitest'
import { renderHook, waitFor } 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 { useAuditEvents } from '../../../../features/admin/audit/useAuditEvents'

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

const server = setupServer()

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

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

function makeEvent(id: number) {
  return {
    id,
    occurredAt: `2026-04-${String(10 + (id % 20)).padStart(2, '0')}T10:00:00Z`,
    actorUserId: 1,
    actorUsername: 'admin',
    action: 'user.created',
    targetType: 'User',
    targetId: String(100 + id),
    correlationId: `corr-${id}`,
    ipAddress: '10.0.0.1',
    metadata: null,
  }
}

describe('useAuditEvents', () => {
  it('fetches the first page (no cursor) and returns items + nextCursor', async () => {
    server.use(
      http.get(`${API_URL}/api/v1/audit/events`, () =>
        HttpResponse.json({
          items: [makeEvent(1), makeEvent(2)],
          nextCursor: 'cursor-page-2',
        }),
      ),
    )

    const { result } = renderHook(() => useAuditEvents({}), {
      wrapper: createWrapper(),
    })

    await waitFor(() => expect(result.current.isSuccess).toBe(true))

    expect(result.current.data?.items).toHaveLength(2)
    expect(result.current.data?.nextCursor).toBe('cursor-page-2')
  })

  it('forwards filters as query params (actor, targetType, targetId, from, to)', async () => {
    let capturedUrl: string | null = null
    server.use(
      http.get(`${API_URL}/api/v1/audit/events`, ({ request }) => {
        capturedUrl = request.url
        return HttpResponse.json({ items: [], nextCursor: null })
      }),
    )

    const { result } = renderHook(
      () =>
        useAuditEvents({
          actor: 42,
          targetType: 'User',
          targetId: 'abc-123',
          from: '2026-04-01T00:00:00Z',
          to: '2026-04-16T23:59:59Z',
        }),
      { wrapper: createWrapper() },
    )

    await waitFor(() => expect(result.current.isSuccess).toBe(true))

    expect(capturedUrl).toContain('actor=42')
    expect(capturedUrl).toContain('targetType=User')
    expect(capturedUrl).toContain('targetId=abc-123')
    expect(capturedUrl).toContain('from=2026-04-01')
    expect(capturedUrl).toContain('to=2026-04-16')
  })

  it('forwards cursor param for successive pages', async () => {
    let capturedUrl: string | null = null
    server.use(
      http.get(`${API_URL}/api/v1/audit/events`, ({ request }) => {
        capturedUrl = request.url
        return HttpResponse.json({
          items: [makeEvent(3)],
          nextCursor: null,
        })
      }),
    )

    const { result } = renderHook(
      () => useAuditEvents({ cursor: 'cursor-page-2' }),
      { wrapper: createWrapper() },
    )

    await waitFor(() => expect(result.current.isSuccess).toBe(true))
    expect(capturedUrl).toContain('cursor=cursor-page-2')
  })

  it('omits undefined/empty filters from the querystring', async () => {
    let capturedUrl: string | null = null
    server.use(
      http.get(`${API_URL}/api/v1/audit/events`, ({ request }) => {
        capturedUrl = request.url
        return HttpResponse.json({ items: [], nextCursor: null })
      }),
    )

    const { result } = renderHook(
      () => useAuditEvents({ actor: 1, targetType: '' }),
      { wrapper: createWrapper() },
    )

    await waitFor(() => expect(result.current.isSuccess).toBe(true))

    expect(capturedUrl).toContain('actor=1')
    expect(capturedUrl).not.toContain('targetType=')
    expect(capturedUrl).not.toContain('from=')
    expect(capturedUrl).not.toContain('to=')
    expect(capturedUrl).not.toContain('cursor=')
  })
})
