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 {
  mockNotification,
  mockNotificationList,
} from '@/test/mocks/data'
import { useNotifications } from '@/hooks/useNotifications'

// ---------------------------------------------------------------------------
// useNotifications
// ---------------------------------------------------------------------------

describe('useNotifications', () => {
  it('returns notifications list and unread count', async () => {
    const { result } = renderHookWithProviders(() => useNotifications())

    // Initially loading
    expect(result.current.loading).toBe(true)
    expect(result.current.notifications).toEqual([])
    expect(result.current.unreadCount).toBe(0)

    await waitFor(() => expect(result.current.loading).toBe(false))

    expect(result.current.notifications).toEqual(mockNotificationList.items)
    expect(result.current.notifications).toHaveLength(2)
    expect(result.current.unreadCount).toBe(1)
    expect(result.current.notifications[0].is_read).toBe(false)
    expect(result.current.notifications[1].is_read).toBe(true)
  })

  it('handles empty notifications', async () => {
    server.use(
      http.get('/api/notifications', () => {
        return HttpResponse.json({ items: [], unread_count: 0 })
      }),
    )

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

    await waitFor(() => expect(result.current.loading).toBe(false))

    expect(result.current.notifications).toEqual([])
    expect(result.current.unreadCount).toBe(0)
  })

  it('handles loading state', async () => {
    const { result } = renderHookWithProviders(() => useNotifications())

    // Should start in loading state
    expect(result.current.loading).toBe(true)
    expect(result.current.notifications).toEqual([])
    expect(result.current.unreadCount).toBe(0)

    // After loading completes
    await waitFor(() => expect(result.current.loading).toBe(false))

    expect(result.current.notifications).toHaveLength(2)
  })

  it('markAsRead mutation works', async () => {
    let capturedId: number | null = null

    server.use(
      http.put('/api/notifications/:id/read', ({ params }) => {
        capturedId = Number(params.id)
        return HttpResponse.json({
          ...mockNotification,
          id: capturedId,
          is_read: true,
        })
      }),
    )

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

    await waitFor(() => expect(result.current.loading).toBe(false))

    await act(async () => {
      result.current.markAsRead(1)
    })

    expect(capturedId).toBe(1)
  })

  it('markAllAsRead mutation works', async () => {
    let markAllCalled = false

    server.use(
      http.put('/api/notifications/read-all', () => {
        markAllCalled = true
        return HttpResponse.json({ marked_read: 1 })
      }),
    )

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

    await waitFor(() => expect(result.current.loading).toBe(false))

    await act(async () => {
      result.current.markAllAsRead()
    })

    expect(markAllCalled).toBe(true)
  })

  it('exposes refresh function', async () => {
    const { result } = renderHookWithProviders(() => useNotifications())

    await waitFor(() => expect(result.current.loading).toBe(false))

    // refresh should be a function
    expect(typeof result.current.refresh).toBe('function')

    // calling refresh should not throw
    await act(async () => {
      result.current.refresh()
    })
  })
})
