/**
 * TDD Phase 1: RED - Write failing tests first
 *
 * This test file follows TDD principles:
 * 1. Tests are written BEFORE implementation
 * 2. Tests describe desired behavior, not implementation
 * 3. Tests should fail initially because Hook doesn't exist
 */

import { renderHook, waitFor, act } from '@testing-library/react-native'
import { useWorksSearch } from '@/hooks/use-works-search'
import { root } from '@repo/core'
import { TemplateGenerationController } from '@repo/sdk'

// Mock dependencies
jest.mock('@repo/core', () => ({
  root: {
    get: jest.fn(),
  },
}))

// Mock @tanstack/react-query before importing the hook
const mockRefetch = jest.fn()
const mockUseQuery = jest.fn(() => ({
  data: undefined,
  isLoading: false,
  error: null,
  refetch: mockRefetch,
}))

jest.mock('@tanstack/react-query', () => ({
  useQuery: jest.fn((args) => mockUseQuery(args)),
}))

describe('useWorksSearch', () => {
  beforeEach(() => {
    jest.clearAllMocks()
  })

  afterEach(() => {
    jest.restoreAllMocks()
  })

  describe('initial state', () => {
    it('should return initial state with no data when no keyword provided', () => {
      // This test will FAIL initially because useWorksSearch doesn't exist yet
      const { result } = renderHook(() => useWorksSearch({ keyword: '' }))

      expect(result.current.data).toBeUndefined()
      expect(result.current.works).toEqual([])
      expect(result.current.isLoading).toBe(false)
      expect(result.current.error).toBeNull()
    })

    it('should not execute query when keyword is empty', () => {
      mockUseQuery.mockReturnValue({
        data: undefined,
        isLoading: false,
        error: null,
        refetch: mockRefetch,
      })

      renderHook(() => useWorksSearch({ keyword: '' }))

      // Verify useQuery was called with enabled: false
      expect(mockUseQuery).toHaveBeenCalledWith(
        expect.objectContaining({
          enabled: false,
        })
      )
    })

    it('should not execute query when keyword is only whitespace', () => {
      mockUseQuery.mockReturnValue({
        data: undefined,
        isLoading: false,
        error: null,
        refetch: mockRefetch,
      })

      renderHook(() => useWorksSearch({ keyword: '   ' }))

      expect(mockUseQuery).toHaveBeenCalledWith(
        expect.objectContaining({
          enabled: false,
        })
      )
    })
  })

  describe('keyword search', () => {
    it('should search works by keyword successfully', async () => {
      const mockData = {
        data: [
          {
            id: '1',
            createdAt: new Date('2025-01-15'),
            template: { id: 'template-1', name: 'Test Template' },
            status: 'completed',
            duration: 5,
          },
          {
            id: '2',
            createdAt: new Date('2025-01-14'),
            template: { id: 'template-2', name: 'Test Template 2' },
            status: 'completed',
            duration: 10,
          },
        ],
        total: 2,
        page: 1,
        limit: 20,
        totalPages: 1,
      }

      mockUseQuery.mockReturnValue({
        data: mockData,
        isLoading: false,
        error: null,
        refetch: mockRefetch,
      })

      const { result } = renderHook(() => useWorksSearch({ keyword: '测试' }))

      expect(result.current.data).toEqual(mockData)
      expect(result.current.works).toEqual(mockData.data)
      expect(result.current.error).toBeNull()
      expect(result.current.isLoading).toBe(false)

      // Verify queryKey includes keyword
      expect(mockUseQuery).toHaveBeenCalledWith(
        expect.objectContaining({
          queryKey: ['worksSearch', '测试', undefined, 1, 20],
        })
      )
    })

    it('should handle search with special characters in keyword', () => {
      const mockData = {
        data: [],
        total: 0,
        page: 1,
        limit: 20,
        totalPages: 0,
      }

      mockUseQuery.mockReturnValue({
        data: mockData,
        isLoading: false,
        error: null,
        refetch: mockRefetch,
      })

      const { result } = renderHook(() => useWorksSearch({ keyword: '测试@#$%' }))

      expect(mockUseQuery).toHaveBeenCalledWith(
        expect.objectContaining({
          queryKey: ['worksSearch', '测试@#$%', undefined, 1, 20],
        })
      )
    })

    it('should execute query when keyword has content', () => {
      mockUseQuery.mockReturnValue({
        data: { data: [], total: 0, page: 1, limit: 20, totalPages: 0 },
        isLoading: false,
        error: null,
        refetch: mockRefetch,
      })

      renderHook(() => useWorksSearch({ keyword: 'test' }))

      expect(mockUseQuery).toHaveBeenCalledWith(
        expect.objectContaining({
          enabled: true,
        })
      )
    })
  })

  describe('category filter', () => {
    it('should filter works by category', () => {
      const mockData = {
        data: [
          {
            id: '1',
            createdAt: new Date('2025-01-15'),
            template: { id: 'template-1', name: 'Test Template' },
            status: 'completed',
            duration: 5,
          },
        ],
        total: 1,
        page: 1,
        limit: 20,
        totalPages: 1,
      }

      mockUseQuery.mockReturnValue({
        data: mockData,
        isLoading: false,
        error: null,
        refetch: mockRefetch,
      })

      const { result } = renderHook(() =>
        useWorksSearch({ keyword: '测试', category: '萌宠' })
      )

      expect(result.current.works).toEqual(mockData.data)

      // Verify queryKey includes category
      expect(mockUseQuery).toHaveBeenCalledWith(
        expect.objectContaining({
          queryKey: ['worksSearch', '测试', '萌宠', 1, 20],
        })
      )
    })

    it('should handle "全部" category by not passing category parameter', () => {
      mockUseQuery.mockReturnValue({
        data: { data: [], total: 0, page: 1, limit: 20, totalPages: 0 },
        isLoading: false,
        error: null,
        refetch: mockRefetch,
      })

      renderHook(() => useWorksSearch({ keyword: '测试', category: '全部' }))

      // "全部" should be excluded from queryKey
      expect(mockUseQuery).toHaveBeenCalledWith(
        expect.objectContaining({
          queryKey: ['worksSearch', '测试', undefined, 1, 20],
        })
      )
    })

    it('should refetch when category changes', () => {
      const mockData1 = {
        data: [{ id: '1', createdAt: new Date(), template: { id: 't1', name: 'T1' }, status: 'completed', duration: 5 }],
        total: 1,
        page: 1,
        limit: 20,
        totalPages: 1,
      }

      const mockData2 = {
        data: [{ id: '2', createdAt: new Date(), template: { id: 't2', name: 'T2' }, status: 'completed', duration: 10 }],
        total: 1,
        page: 1,
        limit: 20,
        totalPages: 1,
      }

      mockUseQuery
        .mockReturnValueOnce({
          data: mockData1,
          isLoading: false,
          error: null,
          refetch: mockRefetch,
        })
        .mockReturnValueOnce({
          data: mockData2,
          isLoading: false,
          error: null,
          refetch: mockRefetch,
        })

      const { result, rerender } = renderHook(
        ({ keyword, category }) => useWorksSearch({ keyword, category }),
        {
          initialProps: { keyword: '测试', category: '萌宠' as const },
        }
      )

      expect(result.current.works).toEqual(mockData1.data)

      // Switch category
      rerender({ keyword: '测试', category: '写真' as const })

      expect(result.current.works).toEqual(mockData2.data)
    })
  })

  describe('pagination', () => {
    it('should load works with custom page and limit', () => {
      mockUseQuery.mockReturnValue({
        data: { data: [], total: 0, page: 2, limit: 10, totalPages: 0 },
        isLoading: false,
        error: null,
        refetch: mockRefetch,
      })

      const { result } = renderHook(() =>
        useWorksSearch({ keyword: '测试', page: 2, limit: 10 })
      )

      expect(mockUseQuery).toHaveBeenCalledWith(
        expect.objectContaining({
          queryKey: ['worksSearch', '测试', undefined, 2, 10],
        })
      )
    })

    it('should use default page 1 and limit 20 when not specified', () => {
      mockUseQuery.mockReturnValue({
        data: { data: [], total: 0, page: 1, limit: 20, totalPages: 0 },
        isLoading: false,
        error: null,
        refetch: mockRefetch,
      })

      renderHook(() => useWorksSearch({ keyword: '测试' }))

      expect(mockUseQuery).toHaveBeenCalledWith(
        expect.objectContaining({
          queryKey: ['worksSearch', '测试', undefined, 1, 20],
        })
      )
    })
  })

  describe('error handling', () => {
    it('should handle API errors', () => {
      const mockError = {
        status: 500,
        statusText: 'Internal Server Error',
        message: 'Failed to search works',
      }

      mockUseQuery.mockReturnValue({
        data: undefined,
        isLoading: false,
        error: mockError,
        refetch: mockRefetch,
      })

      const { result } = renderHook(() => useWorksSearch({ keyword: '测试' }))

      expect(result.current.error).toEqual(mockError)
      expect(result.current.data).toBeUndefined()
      expect(result.current.works).toEqual([])
    })

    it('should handle network errors', () => {
      const networkError = new Error('Network Error')

      mockUseQuery.mockReturnValue({
        data: undefined,
        isLoading: false,
        error: networkError,
        refetch: mockRefetch,
      })

      const { result } = renderHook(() => useWorksSearch({ keyword: '测试' }))

      expect(result.current.error).toEqual(networkError)
    })
  })

  describe('loading state', () => {
    it('should set isLoading to true during fetch', () => {
      mockUseQuery.mockReturnValue({
        data: undefined,
        isLoading: true,
        error: null,
        refetch: mockRefetch,
      })

      const { result } = renderHook(() => useWorksSearch({ keyword: '测试' }))

      expect(result.current.isLoading).toBe(true)
    })

    it('should set isLoading to false after error', () => {
      const mockError = { status: 500, message: 'Error' }

      mockUseQuery.mockReturnValue({
        data: undefined,
        isLoading: false,
        error: mockError,
        refetch: mockRefetch,
      })

      const { result } = renderHook(() => useWorksSearch({ keyword: '测试' }))

      expect(result.current.isLoading).toBe(false)
      expect(result.current.error).toEqual(mockError)
    })
  })

  describe('empty results', () => {
    it('should handle empty search results', () => {
      const mockData = {
        data: [],
        total: 0,
        page: 1,
        limit: 20,
        totalPages: 0,
      }

      mockUseQuery.mockReturnValue({
        data: mockData,
        isLoading: false,
        error: null,
        refetch: mockRefetch,
      })

      const { result } = renderHook(() => useWorksSearch({ keyword: '不存在的关键词' }))

      expect(result.current.data).toEqual(mockData)
      expect(result.current.works).toEqual([])
      expect(result.current.error).toBeNull()
    })
  })
})
