import { describe, it, expect, beforeEach, vi } from 'vitest'
import { ElMessage } from 'element-plus'
import { handleApiError, ApiErrorHandler } from '@/utils/errorHandler'

vi.mock('element-plus', () => ({
  ElMessage: {
    error: vi.fn(),
    success: vi.fn(),
  },
}))

describe('errorHandler', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    vi.stubGlobal('localStorage', {
      removeItem: vi.fn(),
    })
    vi.stubGlobal('window', {
      location: { href: '' },
    })
  })

  describe('handleApiError', () => {
    it('should call ApiErrorHandler.handle', () => {
      const mockError = { response: { status: 500, data: {} } }
      const handleSpy = vi.spyOn(ApiErrorHandler, 'handle')
      
      handleApiError(mockError)
      
      expect(handleSpy).toHaveBeenCalledWith(mockError)
    })
  })

  describe('ApiErrorHandler.handle', () => {
    it('should handle network error', () => {
      const mockError = new Error('Network Error')
      const consoleSpy = vi.spyOn(console, 'error')
      
      ApiErrorHandler.handle(mockError)
      
      expect(ElMessage.error).toHaveBeenCalledWith('网络连接失败，请检查网络设置')
      expect(consoleSpy).toHaveBeenCalledWith('Network Error:', mockError)
    })

    it('should handle 400 Bad Request', () => {
      const mockError = {
        response: {
          status: 400,
          data: { message: 'Invalid parameters' },
        },
      }
      const consoleSpy = vi.spyOn(console, 'error')
      
      ApiErrorHandler.handle(mockError)
      
      expect(ElMessage.error).toHaveBeenCalledWith('Invalid parameters')
      expect(consoleSpy).toHaveBeenCalledWith('Bad Request:', mockError.response.data)
    })

    it('should handle 401 Unauthorized', () => {
      const mockError = {
        response: {
          status: 401,
          data: { message: 'Unauthorized' },
        },
      }
      const consoleSpy = vi.spyOn(console, 'error')
      
      ApiErrorHandler.handle(mockError)
      
      expect(ElMessage.error).toHaveBeenCalledWith('登录已过期，请重新登录')
      expect(localStorage.removeItem).toHaveBeenCalledWith('token')
      expect(window.location.href).toBe('/login')
      expect(consoleSpy).toHaveBeenCalledWith('Unauthorized:', mockError.response.data)
    })

    it('should handle 403 Forbidden', () => {
      const mockError = {
        response: {
          status: 403,
          data: { message: 'Access denied' },
        },
      }
      const consoleSpy = vi.spyOn(console, 'error')
      
      ApiErrorHandler.handle(mockError)
      
      expect(ElMessage.error).toHaveBeenCalledWith('没有权限访问该资源')
      expect(consoleSpy).toHaveBeenCalledWith('Forbidden:', mockError.response.data)
    })

    it('should handle 404 Not Found', () => {
      const mockError = {
        response: {
          status: 404,
          data: { message: 'Resource not found' },
        },
      }
      const consoleSpy = vi.spyOn(console, 'error')
      
      ApiErrorHandler.handle(mockError)
      
      expect(ElMessage.error).toHaveBeenCalledWith('Resource not found')
      expect(consoleSpy).toHaveBeenCalledWith('Not Found:', mockError.response.data)
    })

    it('should handle 409 Conflict', () => {
      const mockError = {
        response: {
          status: 409,
          data: { message: 'Resource conflict' },
        },
      }
      const consoleSpy = vi.spyOn(console, 'error')
      
      ApiErrorHandler.handle(mockError)
      
      expect(ElMessage.error).toHaveBeenCalledWith('Resource conflict')
      expect(consoleSpy).toHaveBeenCalledWith('Conflict:', mockError.response.data)
    })

    it('should handle 422 Validation Error with details', () => {
      const mockError = {
        response: {
          status: 422,
          data: {
            message: 'Validation failed',
            details: {
              username: 'Username is required',
              password: 'Password is too short',
            },
          },
        },
      }
      const consoleSpy = vi.spyOn(console, 'error')
      
      ApiErrorHandler.handle(mockError)
      
      expect(ElMessage.error).toHaveBeenCalledWith('Username is required、Password is too short')
      expect(consoleSpy).toHaveBeenCalledWith('Validation Error:', mockError.response.data)
    })

    it('should handle 422 Validation Error without details', () => {
      const mockError = {
        response: {
          status: 422,
          data: { message: 'Validation failed' },
        },
      }
      const consoleSpy = vi.spyOn(console, 'error')
      
      ApiErrorHandler.handle(mockError)
      
      expect(ElMessage.error).toHaveBeenCalledWith('Validation failed')
      expect(consoleSpy).toHaveBeenCalledWith('Validation Error:', mockError.response.data)
    })

    it('should handle 500 Internal Server Error', () => {
      const mockError = {
        response: {
          status: 500,
          data: { message: 'Server error' },
        },
      }
      const consoleSpy = vi.spyOn(console, 'error')
      
      ApiErrorHandler.handle(mockError)
      
      expect(ElMessage.error).toHaveBeenCalledWith('服务器内部错误，请稍后重试')
      expect(consoleSpy).toHaveBeenCalledWith('Internal Server Error:', mockError.response.data)
    })

    it('should handle 502 Service Unavailable', () => {
      const mockError = {
        response: {
          status: 502,
          data: { message: 'Service unavailable' },
        },
      }
      const consoleSpy = vi.spyOn(console, 'error')
      
      ApiErrorHandler.handle(mockError)
      
      expect(ElMessage.error).toHaveBeenCalledWith('服务暂时不可用，请稍后重试')
      expect(consoleSpy).toHaveBeenCalledWith('Service Unavailable:', mockError.response.data)
    })

    it('should handle 503 Service Unavailable', () => {
      const mockError = {
        response: {
          status: 503,
          data: { message: 'Service unavailable' },
        },
      }
      const consoleSpy = vi.spyOn(console, 'error')
      
      ApiErrorHandler.handle(mockError)
      
      expect(ElMessage.error).toHaveBeenCalledWith('服务暂时不可用，请稍后重试')
      expect(consoleSpy).toHaveBeenCalledWith('Service Unavailable:', mockError.response.data)
    })

    it('should handle 504 Gateway Timeout', () => {
      const mockError = {
        response: {
          status: 504,
          data: { message: 'Gateway timeout' },
        },
      }
      const consoleSpy = vi.spyOn(console, 'error')
      
      ApiErrorHandler.handle(mockError)
      
      expect(ElMessage.error).toHaveBeenCalledWith('服务暂时不可用，请稍后重试')
      expect(consoleSpy).toHaveBeenCalledWith('Service Unavailable:', mockError.response.data)
    })

    it('should handle unknown status code', () => {
      const mockError = {
        response: {
          status: 418,
          data: { message: 'I am a teapot' },
        },
      }
      const consoleSpy = vi.spyOn(console, 'error')
      
      ApiErrorHandler.handle(mockError)
      
      expect(ElMessage.error).toHaveBeenCalledWith('I am a teapot')
      expect(consoleSpy).toHaveBeenCalledWith('Unknown Error:', mockError.response.data)
    })
  })
})
