/**
 * Vitest 测试环境设置
 *
 * 配置全局测试环境和工具
 */

import { vi } from 'vitest'

// Mock window.matchMedia
Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: vi.fn().mockImplementation(query => ({
    matches: false,
    media: query,
    onchange: null,
    addListener: vi.fn(), // Deprecated
    removeListener: vi.fn(), // Deprecated
    addEventListener: vi.fn(),
    removeEventListener: vi.fn(),
    dispatchEvent: vi.fn(),
  })),
})

// Mock IntersectionObserver
global.IntersectionObserver = class IntersectionObserver {
  constructor() {}
  disconnect() {}
  observe() {}
  takeRecords() {
    return []
  }
  unobserve() {}
} as any

// Mock ResizeObserver
global.ResizeObserver = class ResizeObserver {
  constructor() {}
  disconnect() {}
  observe() {}
  unobserve() {}
} as any

// Mock localStorage
const localStorageMock = {
  getItem: (key: string) => null,
  setItem: (key: string, value: string) => {},
  removeItem: (key: string) => {},
  clear: () => {},
}

Object.defineProperty(window, 'localStorage', {
  value: localStorageMock,
})

// Mock sessionStorage
const sessionStorageMock = {
  getItem: (key: string) => null,
  setItem: (key: string, value: string) => {},
  removeItem: (key: string) => {},
  clear: () => {},
}

Object.defineProperty(window, 'sessionStorage', {
  value: sessionStorageMock,
})

// Mock requestAnimationFrame
global.requestAnimationFrame = (callback: FrameRequestCallback) => {
  return setTimeout(callback, 16) as unknown as number
}

global.cancelAnimationFrame = (id: number) => {
  clearTimeout(id)
}

// Mock console方法以减少测试输出
global.console = {
  ...console,
  // Uncomment to ignore console logs during tests
  // log: vi.fn(),
  // debug: vi.fn(),
  // info: vi.fn(),
  // warn: vi.fn(),
  // error: vi.fn(),
}

// 设置全局错误处理
window.addEventListener('error', event => {
  console.error('Global error:', event.error)
})

// 设置未处理的Promise rejection
window.addEventListener('unhandledrejection', event => {
  console.error('Unhandled promise rejection:', event.reason)
})

// Mock URL.createObjectURL和URL.revokeObjectURL
global.URL.createObjectURL = vi.fn(() => 'mock-url')
global.URL.revokeObjectURL = vi.fn()

// Mock navigator
Object.defineProperty(window.navigator, 'userAgent', {
  value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
  writable: true,
})

// Mock scrollTo
window.scrollTo = vi.fn()

// Mock getComputedStyle
window.getComputedStyle = vi.fn(() => ({
  getPropertyValue: (property: string) => {
    const styles: Record<string, string> = {
      display: 'block',
      width: '100px',
      height: '100px',
    }
    return styles[property] || ''
  },
}))

// Mock DOMRect
global.DOMRect = class DOMRect {
  constructor(
    public x = 0,
    public y = 0,
    public width = 0,
    public height = 0,
  ) {}

  toJSON() {
    return {
      x: this.x,
      y: this.y,
      top: this.y,
      left: this.x,
      bottom: this.y + this.height,
      right: this.x + this.width,
      width: this.width,
      height: this.height,
    }
  }

  static fromRect(rect?: DOMRectInit): DOMRect {
    return new DOMRect(rect?.x, rect?.y, rect?.width, rect?.height)
  }
} as any

// Element.prototype.getBoundingClientRect mock
Element.prototype.getBoundingClientRect = new DOMRect(0, 0, 0, 0) as any

// 每个测试前清理
beforeEach(() => {
  vi.clearAllMocks()
})

// 导出测试工具
export const TestUtils = {
  /**
   * 等待组件更新
   */
  async flushPromises(): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, 0))
  },

  /**
   * 创建Mock响应
   */
  createMockResponse<T>(data: T, status = 200): Response {
    return {
      ok: status >= 200 && status < 300,
      status,
      statusText: status === 200 ? 'OK' : 'Error',
      json: async () => data,
      data,
    } as any
  },

  /**
   * 创建Mock API响应
   */
  createMockApiResponse<T>(data: T, code = 200, message = 'success') {
    return {
      code,
      message,
      data,
      timestamp: Date.now(),
    }
  },
}
