/**
 * 个人中心欠款显示单元测试
 * 测试欠款信息显示功能
 */

import { render, screen, waitFor, fireEvent } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import ProfilePage from '@/pages/profile/index'
import { creditBalanceClient } from '@/api'
import { useAuth } from '@/utils/auth'
import { mockShowModal, mockShowLoading, mockHideLoading, mockShowToast, mockReLaunch } from '~/__mocks__/taroMock'

// @tarojs/taro 已经在 jest.config.js 中通过 moduleNameMapper 重定向到 mock 文件
// 不需要额外 mock

// Mock API客户端
jest.mock('@/api', () => ({
  creditBalanceClient: {
    me: {
      $get: jest.fn(),
    },
  },
}))

// Mock 认证hook
jest.mock('@/utils/auth', () => ({
  useAuth: jest.fn(),
}))

// Mock TDesign组件
jest.mock('@/components/tdesign/user-center-card', () => ({
  __esModule: true,
  default: ({ avatar, nickname, isLoggedIn, onUserEdit, className }: any) => (
    <div data-testid="user-center-card" className={className}>
      <div data-testid="avatar">{avatar}</div>
      <div data-testid="nickname">{nickname}</div>
      <div data-testid="is-logged-in">{isLoggedIn ? '已登录' : '未登录'}</div>
      <button data-testid="edit-button" onClick={onUserEdit}>编辑</button>
    </div>
  ),
}))

jest.mock('@/components/tdesign/order-group', () => ({
  __esModule: true,
  default: ({ orderTagInfos, title, desc, onTopClick, onItemClick }: any) => (
    <div data-testid="order-group">
      <div data-testid="order-title">{title}</div>
      <div data-testid="order-desc">{desc}</div>
      <button data-testid="top-click" onClick={onTopClick}>查看全部</button>
      {orderTagInfos.map((item: any, index: number) => (
        <button key={index} data-testid={`order-item-${index}`} onClick={() => onItemClick(item)}>
          {item.title}
        </button>
      ))}
    </div>
  ),
}))

jest.mock('@/components/tdesign/cell-group', () => ({
  __esModule: true,
  default: ({ children }: any) => (
    <div data-testid="cell-group">{children}</div>
  ),
}))

jest.mock('@/components/tdesign/cell', () => ({
  __esModule: true,
  default: ({ title, arrow, bordered, onClick, noteSlot }: any) => (
    <div data-testid="cell" data-bordered={bordered}>
      <div data-testid="cell-title">{title}</div>
      <button data-testid="cell-click" onClick={onClick}>点击</button>
      <div data-testid="cell-note">{noteSlot}</div>
    </div>
  ),
}))

jest.mock('@/components/tdesign/popup', () => ({
  __esModule: true,
  default: ({ visible, placement, onVisibleChange, onClose, children }: any) => (
    visible ? (
      <div data-testid="popup" data-placement={placement}>
        {children}
        <button data-testid="popup-close" onClick={onClose}>关闭</button>
      </div>
    ) : null
  ),
}))

jest.mock('@/components/tdesign/icon', () => ({
  __esModule: true,
  default: ({ name, size, color }: any) => (
    <div data-testid="icon" data-name={name} data-size={size} data-color={color}>图标</div>
  ),
}))

// 创建测试QueryClient
const createTestQueryClient = () => new QueryClient({
  defaultOptions: {
    queries: { retry: false },
    mutations: { retry: false },
  },
})

// Mock CartContext
jest.mock('@/contexts/CartContext', () => ({
  CartProvider: ({ children }: { children: React.ReactNode }) => <>{children}</>,
  useCart: () => ({
    cart: {
      items: [],
      totalAmount: 0,
      totalCount: 0,
    },
    addToCart: jest.fn(),
    removeFromCart: jest.fn(),
    updateQuantity: jest.fn(),
    clearCart: jest.fn(),
    isInCart: jest.fn(),
    getItemQuantity: jest.fn(),
    isLoading: false,
  }),
}))

// 测试包装器
const TestWrapper = ({ children }: { children: React.ReactNode }) => (
  <QueryClientProvider client={createTestQueryClient()}>
    {children}
  </QueryClientProvider>
)

// 测试数据工厂
const createTestUser = (overrides = {}) => ({
  id: 1,
  username: '测试用户',
  avatarFile: { fullUrl: 'https://example.com/avatar.jpg' },
  ...overrides,
})

const createTestCreditBalance = (overrides = {}) => ({
  totalLimit: 1000,
  usedAmount: 200,
  availableAmount: 800,
  isEnabled: true,
  ...overrides,
})

describe('个人中心欠款显示功能测试', () => {
  beforeEach(() => {
    jest.clearAllMocks()

    // 设置默认认证状态
    ;(useAuth as jest.Mock).mockReturnValue({
      user: createTestUser(),
      logout: jest.fn(),
      isLoading: false,
      updateUser: jest.fn(),
    })
  })

  test('应该正确渲染个人中心页面', async () => {
    // Mock 额度查询返回正常数据
    const mockCreditBalance = createTestCreditBalance({ usedAmount: 200 })
    ;(creditBalanceClient.me.$get as jest.Mock).mockResolvedValue({
      status: 200,
      json: () => Promise.resolve(mockCreditBalance),
    })

    render(
      <TestWrapper>
        <ProfilePage />
      </TestWrapper>
    )

    // 验证页面标题
    await waitFor(() => {
      expect(screen.getByText('个人中心')).toBeInTheDocument()
    })

    // 验证用户信息显示
    expect(screen.getByTestId('user-center-card')).toBeInTheDocument()
    expect(screen.getByTestId('nickname')).toHaveTextContent('测试用户')

    // 验证订单组件
    expect(screen.getByTestId('order-group')).toBeInTheDocument()
    expect(screen.getByTestId('order-title')).toHaveTextContent('我的订单')
  })

  test('有欠款时应该显示欠款信息卡片', async () => {
    // Mock 额度查询返回有欠款的数据
    const mockCreditBalance = createTestCreditBalance({ usedAmount: 200 })
    ;(creditBalanceClient.me.$get as jest.Mock).mockResolvedValue({
      status: 200,
      json: () => Promise.resolve(mockCreditBalance),
    })

    render(
      <TestWrapper>
        <ProfilePage />
      </TestWrapper>
    )

    // 等待额度加载完成
    await waitFor(() => {
      expect(screen.getByText('欠款信息')).toBeInTheDocument()
    })

    // 验证欠款信息显示
    expect(screen.getByText('累计欠款')).toBeInTheDocument()
    expect(screen.getByText('¥200.00')).toBeInTheDocument()
    expect(screen.getByText('需结清金额')).toBeInTheDocument()
    expect(screen.getByText('请及时还款')).toBeInTheDocument()
  })

  test('没有欠款时不应该显示欠款信息卡片', async () => {
    // Mock 额度查询返回没有欠款的数据
    const mockCreditBalance = createTestCreditBalance({ usedAmount: 0 })
    ;(creditBalanceClient.me.$get as jest.Mock).mockResolvedValue({
      status: 200,
      json: () => Promise.resolve(mockCreditBalance),
    })

    render(
      <TestWrapper>
        <ProfilePage />
      </TestWrapper>
    )

    // 等待额度加载完成（如果有查询）
    await waitFor(() => {
      // 验证没有显示欠款信息卡片
      expect(screen.queryByText('欠款信息')).not.toBeInTheDocument()
      expect(screen.queryByText('累计欠款')).not.toBeInTheDocument()
    })
  })

  test('额度查询加载中应该显示加载状态', async () => {
    // Mock 额度查询延迟返回
    let resolveQuery: any
    const queryPromise = new Promise((resolve) => {
      resolveQuery = resolve
    })
    ;(creditBalanceClient.me.$get as jest.Mock).mockReturnValue(queryPromise)

    render(
      <TestWrapper>
        <ProfilePage />
      </TestWrapper>
    )

    // 验证加载状态显示 - 使用更灵活的选择器
    await waitFor(() => {
      const loadingElement = screen.getByText(/加载中/)
      expect(loadingElement).toBeInTheDocument()
    })

    // 解析查询
    const mockCreditBalance = createTestCreditBalance({ usedAmount: 200 })
    resolveQuery({
      status: 200,
      json: () => Promise.resolve(mockCreditBalance),
    })

    // 等待加载完成
    await waitFor(() => {
      expect(screen.queryByText(/加载中/)).not.toBeInTheDocument()
      expect(screen.getByText('欠款信息')).toBeInTheDocument()
    })
  })

  test('额度查询失败应该显示错误状态', async () => {
    // Mock 额度查询失败
    ;(creditBalanceClient.me.$get as jest.Mock).mockRejectedValue(new Error('网络错误'))

    render(
      <TestWrapper>
        <ProfilePage />
      </TestWrapper>
    )

    // 等待错误状态显示
    await waitFor(() => {
      expect(screen.getByText('加载失败')).toBeInTheDocument()
      expect(screen.getByText('重新加载')).toBeInTheDocument()
    })
  })

  test('额度查询失败后可以重试', async () => {
    // Mock 额度查询第一次失败，第二次成功
    let callCount = 0
    ;(creditBalanceClient.me.$get as jest.Mock).mockImplementation(() => {
      callCount++
      if (callCount === 1) {
        return Promise.reject(new Error('网络错误'))
      } else {
        return Promise.resolve({
          status: 200,
          json: () => Promise.resolve(createTestCreditBalance({ usedAmount: 200 })),
        })
      }
    })

    render(
      <TestWrapper>
        <ProfilePage />
      </TestWrapper>
    )

    // 等待错误状态显示
    await waitFor(() => {
      expect(screen.getByText('加载失败')).toBeInTheDocument()
    })

    // 点击重新加载按钮
    const retryButton = screen.getByText('重新加载')
    fireEvent.click(retryButton)

    // 等待重试成功
    await waitFor(() => {
      expect(screen.getByText('欠款信息')).toBeInTheDocument()
      expect(screen.getByText('¥200.00')).toBeInTheDocument()
    })
  })

  test('用户未登录时应该显示登录提示', async () => {
    // Mock 用户未登录
    ;(useAuth as jest.Mock).mockReturnValue({
      user: null,
      logout: jest.fn(),
      isLoading: false,
      updateUser: jest.fn(),
    })

    render(
      <TestWrapper>
        <ProfilePage />
      </TestWrapper>
    )

    // 验证登录提示
    expect(screen.getByText('请先登录')).toBeInTheDocument()
    expect(screen.getByText('去登录')).toBeInTheDocument()

    // 验证没有显示欠款信息
    expect(screen.queryByText('欠款信息')).not.toBeInTheDocument()
  })

  test('额度查询返回404时不应该显示欠款信息', async () => {
    // Mock 额度查询返回404（用户没有额度记录）
    ;(creditBalanceClient.me.$get as jest.Mock).mockResolvedValue({
      status: 404,
      json: () => Promise.resolve({ message: '用户信用额度记录不存在' }),
    })

    render(
      <TestWrapper>
        <ProfilePage />
      </TestWrapper>
    )

    // 等待查询完成
    await waitFor(() => {
      // 验证没有显示欠款信息卡片
      expect(screen.queryByText('欠款信息')).not.toBeInTheDocument()
    })
  })

  test('欠款金额较大时应该正确格式化显示', async () => {
    // Mock 额度查询返回大额欠款
    const mockCreditBalance = createTestCreditBalance({ usedAmount: 12345.67 })
    ;(creditBalanceClient.me.$get as jest.Mock).mockResolvedValue({
      status: 200,
      json: () => Promise.resolve(mockCreditBalance),
    })

    render(
      <TestWrapper>
        <ProfilePage />
      </TestWrapper>
    )

    // 等待额度加载完成
    await waitFor(() => {
      expect(screen.getByText('欠款信息')).toBeInTheDocument()
    })

    // 验证金额正确格式化 - 使用正则表达式匹配
    expect(screen.getByText(/¥12,345\.67/)).toBeInTheDocument()
  })

  test('应该正确显示欠款卡片的样式', async () => {
    // Mock 额度查询返回有欠款的数据
    const mockCreditBalance = createTestCreditBalance({ usedAmount: 200 })
    ;(creditBalanceClient.me.$get as jest.Mock).mockResolvedValue({
      status: 200,
      json: () => Promise.resolve(mockCreditBalance),
    })

    render(
      <TestWrapper>
        <ProfilePage />
      </TestWrapper>
    )

    // 等待额度加载完成
    await waitFor(() => {
      expect(screen.getByText('欠款信息')).toBeInTheDocument()
    })

    // 验证卡片结构
    const card = screen.getByText('欠款信息').closest('.bg-white')
    expect(card).toBeInTheDocument()
    expect(card).toHaveClass('rounded-2xl')

    // 验证标题区域
    const titleSection = screen.getByText('欠款信息').closest('.border-b')
    expect(titleSection).toBeInTheDocument()
    expect(titleSection).toHaveClass('border-gray-100')

    // 验证金额显示为大字体
    const amountText = screen.getByText('¥200.00')
    expect(amountText).toHaveClass('text-2xl')
    expect(amountText).toHaveClass('font-bold')
    expect(amountText).toHaveClass('text-red-600')

    // 验证图标显示
    const iconContainer = screen.getByText('📊').closest('.bg-red-100')
    expect(iconContainer).toBeInTheDocument()
    expect(iconContainer).toHaveClass('rounded-full')
  })
})