import { describe, it, expect } from 'vitest'
import { waitFor, act } from '@testing-library/react'
import { http, HttpResponse } from 'msw'
import { server } from '@/test/mocks/server'
import { renderHookWithProviders } from '@/test/utils'
import { mockUserResponse } from '@/test/mocks/data'
import { useUsers, useCreateUser, useUpdateUser } from '@/hooks/useUsers'

// ---------------------------------------------------------------------------
// useUsers
// ---------------------------------------------------------------------------

describe('useUsers', () => {
  it('fetches user list (success)', async () => {
    const { result } = renderHookWithProviders(() => useUsers())

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

    expect(result.current.data).toEqual([mockUserResponse])
    expect(result.current.data).toHaveLength(1)
    expect(result.current.data![0].username).toBe('admin_user')
    expect(result.current.data![0].role).toBe('admin')
  })

  it('handles empty list', async () => {
    server.use(
      http.get('/api/admin/users', () => {
        return HttpResponse.json([])
      }),
    )

    const { result } = renderHookWithProviders(() => useUsers())

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

    expect(result.current.data).toEqual([])
    expect(result.current.data).toHaveLength(0)
  })
})

// ---------------------------------------------------------------------------
// useCreateUser
// ---------------------------------------------------------------------------

describe('useCreateUser', () => {
  it('creates user (success)', async () => {
    const newUser = {
      ...mockUserResponse,
      id: 3,
      username: 'new_user',
      email: 'new@dak.de',
      role: 'dak_mitarbeiter' as const,
    }

    server.use(
      http.post('/api/admin/users', () => {
        return HttpResponse.json(newUser)
      }),
    )

    const { result } = renderHookWithProviders(() => useCreateUser())

    let response: unknown
    await act(async () => {
      response = await result.current.mutateAsync({
        username: 'new_user',
        email: 'new@dak.de',
        password: 'SecurePass123!',
        role: 'dak_mitarbeiter',
      })
    })

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

    expect((response as { id: number }).id).toBe(3)
    expect((response as { username: string }).username).toBe('new_user')
    expect((response as { role: string }).role).toBe('dak_mitarbeiter')
  })

  it('handles validation error (422)', async () => {
    server.use(
      http.post('/api/admin/users', () => {
        return HttpResponse.json(
          { detail: 'Username already exists' },
          { status: 422 },
        )
      }),
    )

    const { result } = renderHookWithProviders(() => useCreateUser())

    await act(async () => {
      try {
        await result.current.mutateAsync({
          username: 'admin_user',
          email: 'duplicate@dak.de',
          password: 'SecurePass123!',
          role: 'admin',
        })
      } catch {
        // expected
      }
    })

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

// ---------------------------------------------------------------------------
// useUpdateUser
// ---------------------------------------------------------------------------

describe('useUpdateUser', () => {
  it('updates user (success)', async () => {
    const updatedUser = {
      ...mockUserResponse,
      role: 'dak_mitarbeiter' as const,
      is_active: false,
    }

    server.use(
      http.put('/api/admin/users/:id', () => {
        return HttpResponse.json(updatedUser)
      }),
    )

    const { result } = renderHookWithProviders(() => useUpdateUser())

    let response: unknown
    await act(async () => {
      response = await result.current.mutateAsync({
        id: 1,
        payload: { role: 'dak_mitarbeiter', is_active: false },
      })
    })

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

    expect((response as { role: string }).role).toBe('dak_mitarbeiter')
    expect((response as { is_active: boolean }).is_active).toBe(false)
  })

  it('handles error (404 Not Found)', async () => {
    server.use(
      http.put('/api/admin/users/:id', () => {
        return HttpResponse.json(
          { detail: 'User not found' },
          { status: 404 },
        )
      }),
    )

    const { result } = renderHookWithProviders(() => useUpdateUser())

    await act(async () => {
      try {
        await result.current.mutateAsync({
          id: 999,
          payload: { is_active: false },
        })
      } catch {
        // expected
      }
    })

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