import { describe, it, expect, vi } from 'vitest'
import { render, screen, fireEvent } from '@testing-library/react'
import { Button } from '../../basic/button'
import { createRef } from 'react'

describe('Button', () => {
  // ============================================================
  // 渲染测试
  // ============================================================
  describe('渲染', () => {
    it('应正确渲染 children 文本', () => {
      render(<Button>点击我</Button>)
      expect(screen.getByRole('button')).toHaveTextContent('点击我')
    })

    it('应渲染为原生 button 元素', () => {
      render(<Button>按钮</Button>)
      expect(screen.getByRole('button').tagName).toBe('BUTTON')
    })

    it('应设置正确的 displayName', () => {
      expect(Button.displayName).toBe('Button')
    })
  })

  // ============================================================
  // Variant 变体测试
  // ============================================================
  describe('variant 变体', () => {
    it('默认应使用 ghost 变体', () => {
      render(<Button>Ghost</Button>)
      expect(screen.getByRole('button')).toHaveClass('bg-transparent')
    })

    it('variant="primary" 应应用主色样式', () => {
      render(<Button variant="primary">Primary</Button>)
      expect(screen.getByRole('button')).toHaveClass('bg-primary')
    })

    it('variant="secondary" 应应用次级样式', () => {
      render(<Button variant="secondary">Secondary</Button>)
      expect(screen.getByRole('button')).toHaveClass('bg-bg-highlight')
    })

    it('variant="tertiary" 应应用三级样式', () => {
      render(<Button variant="tertiary">Tertiary</Button>)
      expect(screen.getByRole('button')).toHaveClass('bg-fill-secondary')
    })

    it('variant="text" 应应用纯文字样式', () => {
      render(<Button variant="text">Text</Button>)
      expect(screen.getByRole('button')).toHaveClass('bg-transparent')
      expect(screen.getByRole('button')).toHaveClass('text-text-secondary')
    })
  })

  // ============================================================
  // Size 尺寸测试
  // ============================================================
  describe('size 尺寸', () => {
    it('默认应使用 md 尺寸', () => {
      render(<Button>Medium</Button>)
      expect(screen.getByRole('button')).toHaveClass('h-[var(--control-height-md)]')
    })

    it('size="sm" 应应用小尺寸样式', () => {
      render(<Button size="sm">Small</Button>)
      expect(screen.getByRole('button')).toHaveClass('h-[var(--control-height-sm)]')
      expect(screen.getByRole('button')).toHaveClass('text-[length:var(--control-font-size-sm)]')
    })

    it('size="md" 应应用中等尺寸样式', () => {
      render(<Button size="md">Medium</Button>)
      expect(screen.getByRole('button')).toHaveClass('h-[var(--control-height-md)]')
      expect(screen.getByRole('button')).toHaveClass('text-[length:var(--control-font-size-md)]')
    })

    it('size="lg" 应应用大尺寸样式', () => {
      render(<Button size="lg">Large</Button>)
      expect(screen.getByRole('button')).toHaveClass('h-[var(--control-height-lg)]')
      expect(screen.getByRole('button')).toHaveClass('text-[length:var(--control-font-size-lg)]')
    })
  })

  // ============================================================
  // Rounded 圆角测试
  // ============================================================
  describe('rounded 圆角', () => {
    it('默认应使用 square 圆角', () => {
      render(<Button>Square</Button>)
      expect(screen.getByRole('button')).toHaveClass('rounded')
      expect(screen.getByRole('button')).not.toHaveClass('rounded-full')
    })

    it('rounded="pill" 应应用全圆角样式', () => {
      render(<Button rounded="pill">Pill</Button>)
      expect(screen.getByRole('button')).toHaveClass('rounded-full')
    })
  })

  // ============================================================
  // textButton 模式测试
  // ============================================================
  describe('textButton 模式', () => {
    it('textButton=true 应移除高度和内边距', () => {
      render(<Button textButton>Text Only</Button>)
      const button = screen.getByRole('button')
      expect(button).toHaveClass('h-auto')
      expect(button).toHaveClass('px-[var(--control-text-padding-x)]')
    })

    it('textButton=true 应强制使用 text 变体样式', () => {
      render(<Button textButton variant="primary">Text</Button>)
      const button = screen.getByRole('button')
      // 即使传入 primary，textButton 也会覆盖为 text 变体
      expect(button).toHaveClass('bg-transparent')
    })

    it('textButton 应保留正确的字体大小', () => {
      const { rerender } = render(<Button textButton size="sm">SM</Button>)
      expect(screen.getByRole('button')).toHaveClass('text-[length:var(--control-font-size-sm)]')

      rerender(<Button textButton size="md">MD</Button>)
      expect(screen.getByRole('button')).toHaveClass('text-[length:var(--control-font-size-md)]')

      rerender(<Button textButton size="lg">LG</Button>)
      expect(screen.getByRole('button')).toHaveClass('text-[length:var(--control-font-size-lg)]')
    })
  })

  // ============================================================
  // 图标测试
  // ============================================================
  describe('图标', () => {
    it('应渲染 prefixIcon', () => {
      render(
        <Button prefixIcon={<span data-testid="prefix">←</span>}>
          有前置图标
        </Button>
      )
      expect(screen.getByTestId('prefix')).toBeInTheDocument()
      expect(screen.getByTestId('prefix')).toHaveTextContent('←')
    })

    it('应渲染 suffixIcon', () => {
      render(
        <Button suffixIcon={<span data-testid="suffix">→</span>}>
          有后置图标
        </Button>
      )
      expect(screen.getByTestId('suffix')).toBeInTheDocument()
      expect(screen.getByTestId('suffix')).toHaveTextContent('→')
    })

    it('应同时渲染前后置图标', () => {
      render(
        <Button
          prefixIcon={<span data-testid="prefix">←</span>}
          suffixIcon={<span data-testid="suffix">→</span>}
        >
          双图标
        </Button>
      )
      expect(screen.getByTestId('prefix')).toBeInTheDocument()
      expect(screen.getByTestId('suffix')).toBeInTheDocument()
    })

    it('无图标时不应渲染图标包裹元素', () => {
      const { container } = render(<Button>无图标</Button>)
      // 检查没有图标包裹的 span 元素
      const iconWrappers = container.querySelectorAll('button > span.inline-flex')
      expect(iconWrappers).toHaveLength(0)
    })
  })

  // ============================================================
  // 交互测试
  // ============================================================
  describe('交互', () => {
    it('点击时应触发 onClick 回调', () => {
      const handleClick = vi.fn()
      render(<Button onClick={handleClick}>点击</Button>)

      fireEvent.click(screen.getByRole('button'))
      expect(handleClick).toHaveBeenCalledTimes(1)
    })

    it('多次点击应触发相应次数的回调', () => {
      const handleClick = vi.fn()
      render(<Button onClick={handleClick}>点击</Button>)

      const button = screen.getByRole('button')
      fireEvent.click(button)
      fireEvent.click(button)
      fireEvent.click(button)

      expect(handleClick).toHaveBeenCalledTimes(3)
    })
  })

  // ============================================================
  // Disabled 状态测试
  // ============================================================
  describe('disabled 状态', () => {
    it('disabled=true 应设置 disabled 属性', () => {
      render(<Button disabled>禁用</Button>)
      expect(screen.getByRole('button')).toBeDisabled()
    })

    it('disabled 时应应用禁用样式', () => {
      render(<Button disabled>禁用</Button>)
      expect(screen.getByRole('button')).toHaveClass('disabled:opacity-50')
      expect(screen.getByRole('button')).toHaveClass('disabled:cursor-not-allowed')
    })

    it('disabled 时点击不应触发 onClick', () => {
      const handleClick = vi.fn()
      render(<Button disabled onClick={handleClick}>禁用</Button>)

      fireEvent.click(screen.getByRole('button'))
      expect(handleClick).not.toHaveBeenCalled()
    })

    it('默认不应禁用', () => {
      render(<Button>正常</Button>)
      expect(screen.getByRole('button')).not.toBeDisabled()
    })
  })

  // ============================================================
  // Ref 转发测试
  // ============================================================
  describe('ref 转发', () => {
    it('应正确转发 ref 到 button 元素', () => {
      const ref = createRef<HTMLButtonElement>()
      render(<Button ref={ref}>带 Ref</Button>)

      expect(ref.current).toBeInstanceOf(HTMLButtonElement)
    })

    it('ref.current 应指向渲染的 button', () => {
      const ref = createRef<HTMLButtonElement>()
      render(<Button ref={ref}>带 Ref</Button>)

      expect(ref.current).toBe(screen.getByRole('button'))
    })

    it('callback ref 应被正确调用', () => {
      const callbackRef = vi.fn()
      render(<Button ref={callbackRef}>Callback Ref</Button>)

      expect(callbackRef).toHaveBeenCalled()
      expect(callbackRef.mock.calls[0][0]).toBeInstanceOf(HTMLButtonElement)
    })
  })

  // ============================================================
  // className 覆盖测试
  // ============================================================
  describe('className 覆盖', () => {
    it('应合并自定义 className', () => {
      render(<Button className="custom-class">自定义类</Button>)
      expect(screen.getByRole('button')).toHaveClass('custom-class')
    })

    it('自定义 className 应与默认类名共存', () => {
      render(<Button className="my-custom" variant="primary">合并类</Button>)
      const button = screen.getByRole('button')
      expect(button).toHaveClass('my-custom')
      expect(button).toHaveClass('bg-primary')
    })
  })

  // ============================================================
  // 原生属性透传测试
  // ============================================================
  describe('原生属性透传', () => {
    it('应透传 type 属性', () => {
      render(<Button type="submit">提交</Button>)
      expect(screen.getByRole('button')).toHaveAttribute('type', 'submit')
    })

    it('应透传 aria-label 属性', () => {
      render(<Button aria-label="关闭按钮">×</Button>)
      expect(screen.getByRole('button')).toHaveAttribute('aria-label', '关闭按钮')
    })

    it('应透传 data-* 属性', () => {
      render(<Button data-testid="my-button">测试</Button>)
      expect(screen.getByTestId('my-button')).toBeInTheDocument()
    })

    it('应透传 id 属性', () => {
      render(<Button id="unique-button">ID 按钮</Button>)
      expect(screen.getByRole('button')).toHaveAttribute('id', 'unique-button')
    })
  })

  // ============================================================
  // 组合场景测试
  // ============================================================
  describe('组合场景', () => {
    it('应支持所有 props 组合', () => {
      const handleClick = vi.fn()
      render(
        <Button
          variant="primary"
          size="lg"
          rounded="pill"
          prefixIcon={<span>🚀</span>}
          suffixIcon={<span>✨</span>}
          onClick={handleClick}
          className="extra-class"
          data-testid="combo-button"
        >
          组合按钮
        </Button>
      )

      const button = screen.getByTestId('combo-button')
      expect(button).toHaveClass('bg-primary')
      expect(button).toHaveClass('h-[var(--control-height-lg)]')
      expect(button).toHaveClass('rounded-full')
      expect(button).toHaveClass('extra-class')
      expect(button).toHaveTextContent('🚀')
      expect(button).toHaveTextContent('组合按钮')
      expect(button).toHaveTextContent('✨')

      fireEvent.click(button)
      expect(handleClick).toHaveBeenCalled()
    })
  })
})
