import React from 'react'
import { renderHook, waitFor } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { AuthProvider, useRequireAuth } from '../../src/hooks/useAuth'
import Taro from '@tarojs/taro'

// Mock Taro
jest.mock('@tarojs/taro', () => ({
  showToast: jest.fn(),
  redirectTo: jest.fn(),
  getStorageSync: jest.fn(() => null),
  setStorageSync: jest.fn(),
  removeStorageSync: jest.fn(),
}))

// Mock talentAuthClient
jest.mock('../../src/api', () => ({
  talentAuthClient: {
    me: {
      $get: jest.fn(),
    },
    login: {
      $post: jest.fn(),
    },
  },
}))

const mockToast = Taro.showToast as jest.MockedFunction<typeof Taro.showToast>
const mockRedirectTo = Taro.redirectTo as jest.MockedFunction<typeof Taro.redirectTo>

describe('useRequireAuth', () => {
  let queryClient: QueryClient

  const wrapper = ({ children }: { children: React.ReactNode }) => (
    <QueryClientProvider client={queryClient}>
      <AuthProvider>{children}</AuthProvider>
    </QueryClientProvider>
  )

  beforeEach(() => {
    queryClient = new QueryClient({
      defaultOptions: {
        queries: {
          retry: false,
          staleTime: Infinity,
          refetchOnWindowFocus: false,
          refetchOnReconnect: false,
        },
      },
    })
    jest.clearAllMocks()
    jest.useFakeTimers()
  })

  afterEach(() => {
    queryClient.clear()
    jest.useRealTimers()
  })

  it('应该在未登录时显示提示并跳转到登录页', async () => {
    // 模拟无token的情况
    ;(Taro.getStorageSync as jest.Mock).mockReturnValue(null)

    renderHook(() => useRequireAuth(), { wrapper })

    // 等待useEffect执行
    await waitFor(() => {
      expect(mockToast).toHaveBeenCalledWith({
        title: '请先登录',
        icon: 'none',
        duration: 1500,
      })
    })

    // 快进1500ms
    jest.advanceTimersByTime(1500)

    // 等待redirectTo被调用
    await waitFor(() => {
      expect(mockRedirectTo).toHaveBeenCalledWith({
        url: '/pages/login/index',
      })
    })
  })

  it('应该在loading状态时不跳转', async () => {
    // 模拟无token但loading中的情况
    ;(Taro.getStorageSync as jest.Mock).mockReturnValue(null)

    const { result } = renderHook(() => useRequireAuth(), { wrapper })

    // 在初始加载期间不应该立即调用redirectTo（需要等待loading结束）
    // 由于我们模拟的token为null，loading会很快结束
    // 这里我们只验证在第一次render时不会调用
    expect(mockRedirectTo).not.toHaveBeenCalled()
  })

  it('应该在已登录时不跳转', async () => {
    // 模拟有token且已登录的情况
    ;(Taro.getStorageSync as jest.Mock).mockReturnValue('valid_token')

    // 模拟API返回用户信息
    const { talentAuthClient } = require('../../src/api')
    talentAuthClient.me.$get.mockResolvedValue({
      status: 200,
      json: async () => ({ id: 1, name: '测试用户' }),
    })

    renderHook(() => useRequireAuth(), { wrapper })

    // 等待查询完成
    await waitFor(() => {
      expect(talentAuthClient.me.$get).toHaveBeenCalled()
    })

    // 已登录状态不应该调用redirectTo
    expect(mockRedirectTo).not.toHaveBeenCalled()
  })

  it('应该在token失效时清除token并跳转', async () => {
    // 模拟有token但API返回错误的情况
    ;(Taro.getStorageSync as jest.Mock).mockReturnValue('invalid_token')

    const { talentAuthClient } = require('../../src/api')
    talentAuthClient.me.$get.mockResolvedValue({
      status: 401,
    })

    renderHook(() => useRequireAuth(), { wrapper })

    // 等待查询完成并验证token被清除
    await waitFor(() => {
      expect(Taro.removeStorageSync).toHaveBeenCalledWith('talent_token')
      expect(Taro.removeStorageSync).toHaveBeenCalledWith('talent_user')
    })

    // 快进1500ms
    jest.advanceTimersByTime(1500)

    // 验证跳转到登录页
    await waitFor(() => {
      expect(mockRedirectTo).toHaveBeenCalledWith({
        url: '/pages/login/index',
      })
    })
  })
})
