/**
 * 个人中心编辑资料功能单元测试
 * 测试头像和昵称编辑功能
 */

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 Taro from '@tarojs/taro'

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

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

// Mock TDesign组件 - 复用现有测试中的mock
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, 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, 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>
  ),
}))

// Mock AvatarUpload组件
jest.mock('@/components/ui/avatar-upload', () => ({
  AvatarUpload: ({
    currentAvatar,
    onUploadSuccess,
    onUploadError,
    editable
  }: any) => (
    <div data-testid="avatar-upload" data-editable={editable}>
      <img src={currentAvatar} alt="头像" data-testid="avatar-image" />
      <button
        data-testid="upload-button"
        onClick={() => {
          // 模拟上传成功
          if (editable) {
            onUploadSuccess?.({
              fileUrl: 'https://example.com/new-avatar.jpg',
              fileId: 456,
              fileKey: 'avatars/new-avatar.jpg',
              bucketName: 'd8dai'
            })
          }
        }}
      >
        上传头像
      </button>
      <button
        data-testid="upload-error-button"
        onClick={() => {
          onUploadError?.(new Error('模拟上传失败'))
        }}
      >
        模拟上传失败
      </button>
    </div>
  ),
}))

// Mock Taro组件 - 输入框
jest.mock('@tarojs/components', () => ({
  View: ({ children, ...props }: any) => <div {...props}>{children}</div>,
  Text: ({ children, ...props }: any) => <span {...props}>{children}</span>,
  ScrollView: ({ children, ...props }: any) => <div {...props}>{children}</div>,
  Input: ({ value, onInput, placeholder, maxlength, className }: any) => (
    <input
      data-testid="nickname-input"
      value={value}
      onChange={(e) => onInput?.({ detail: { value: e.target.value } })}
      placeholder={placeholder}
      maxLength={maxlength}
      className={className}
    />
  ),
}))

// Mock Button组件
jest.mock('@/components/ui/button', () => ({
  Button: ({ variant, size, className, onClick, children }: any) => (
    <button
      data-testid={`button-${variant}`}
      data-size={size}
      className={className}
      onClick={onClick}
    >
      {children}
    </button>
  ),
}))

// 创建测试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: {
    id: 123,
    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(),
      refreshUser: jest.fn(),
    })

    // 设置默认额度查询
    ;(creditBalanceClient.me.$get as jest.Mock).mockResolvedValue({
      status: 200,
      json: () => Promise.resolve(createTestCreditBalance({ usedAmount: 0 })),
    })
  })

  test('应该正确渲染个人中心页面', async () => {
    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('avatar')).toHaveTextContent('https://example.com/avatar.jpg')
  })

  test('应该打开编辑资料弹窗并显示当前头像和昵称', async () => {
    render(
      <TestWrapper>
        <ProfilePage />
      </TestWrapper>
    )

    // 点击编辑按钮打开弹窗
    fireEvent.click(screen.getByTestId('edit-button'))

    // 验证弹窗显示
    expect(screen.getByTestId('popup')).toBeInTheDocument()

    // 验证头像显示正确
    const avatarImage = screen.getByTestId('avatar-image') as HTMLImageElement
    expect(avatarImage.src).toBe('https://example.com/avatar.jpg')

    // 验证昵称输入框显示正确
    const nicknameInput = screen.getByTestId('nickname-input') as HTMLInputElement
    expect(nicknameInput.value).toBe('测试用户')
  })

  test('头像上传成功应该调用updateUser和refreshUser', async () => {
    const mockUpdateUser = jest.fn()
    const mockRefreshUser = jest.fn()

    // 设置模拟函数
    ;(useAuth as jest.Mock).mockReturnValue({
      user: createTestUser(),
      logout: jest.fn(),
      isLoading: false,
      updateUser: mockUpdateUser,
      refreshUser: mockRefreshUser,
    })
    // 设置mock返回值，确保异步流程正常执行
    mockUpdateUser.mockResolvedValue(createTestUser())
    mockRefreshUser.mockResolvedValue(createTestUser())

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

    // 打开编辑弹窗
    fireEvent.click(screen.getByTestId('edit-button'))

    // 点击上传按钮（模拟上传成功）
    fireEvent.click(screen.getByTestId('upload-button'))

    // 验证updateUser被调用，参数包含新的fileId
    await waitFor(() => {
      expect(mockUpdateUser).toHaveBeenCalledWith({ avatarFileId: 456 })
    })

    // 验证refreshUser被调用
    await waitFor(() => {
      expect(mockRefreshUser).toHaveBeenCalled()
    })
  })

  test('头像上传失败应该显示错误提示', async () => {
    // Mock Taro.showToast
    const mockShowToast = jest.fn()
    ;(Taro as any).showToast = mockShowToast

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

    // 打开编辑弹窗
    fireEvent.click(screen.getByTestId('edit-button'))

    // 点击模拟上传失败按钮
    fireEvent.click(screen.getByTestId('upload-error-button'))

    // 验证错误提示被调用
    expect(mockShowToast).toHaveBeenCalledWith({
      title: '模拟上传失败',
      icon: 'none',
      duration: 3000,
    })
  })

  test('昵称修改应该调用updateUser和refreshUser', async () => {
    const mockUpdateUser = jest.fn()
    const mockRefreshUser = jest.fn()

    // 设置模拟函数
    ;(useAuth as jest.Mock).mockReturnValue({
      user: createTestUser(),
      logout: jest.fn(),
      isLoading: false,
      updateUser: mockUpdateUser,
      refreshUser: mockRefreshUser,
    })
    // 设置mock返回值，确保异步流程正常执行
    mockUpdateUser.mockResolvedValue(createTestUser())
    mockRefreshUser.mockResolvedValue(createTestUser())

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

    // 打开编辑弹窗
    fireEvent.click(screen.getByTestId('edit-button'))

    // 修改昵称输入框
    const nicknameInput = screen.getByTestId('nickname-input')
    fireEvent.change(nicknameInput, { target: { value: '新昵称' } })

    // 点击保存按钮
    fireEvent.click(screen.getByTestId('button-default'))

    // 验证updateUser被调用，参数包含新昵称
    await waitFor(() => {
      expect(mockUpdateUser).toHaveBeenCalledWith({ username: '新昵称' })
    })

    // 验证refreshUser被调用
    await waitFor(() => {
      expect(mockRefreshUser).toHaveBeenCalled()
    })
  })

  test('同时修改头像和昵称应该调用updateUser包含两个字段', async () => {
    const mockUpdateUser = jest.fn()
    const mockRefreshUser = jest.fn()

    // 设置模拟函数
    ;(useAuth as jest.Mock).mockReturnValue({
      user: createTestUser(),
      logout: jest.fn(),
      isLoading: false,
      updateUser: mockUpdateUser,
      refreshUser: mockRefreshUser,
    })
    // 设置mock返回值，确保异步流程正常执行
    mockUpdateUser.mockResolvedValue(createTestUser())
    mockRefreshUser.mockResolvedValue(createTestUser())

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

    // 打开编辑弹窗
    fireEvent.click(screen.getByTestId('edit-button'))

    // 上传新头像
    fireEvent.click(screen.getByTestId('upload-button'))

    // 修改昵称
    const nicknameInput = screen.getByTestId('nickname-input')
    fireEvent.change(nicknameInput, { target: { value: '新昵称' } })

    // 点击保存按钮
    fireEvent.click(screen.getByTestId('button-default'))

    // 验证updateUser被调用，参数包含两个字段
    await waitFor(() => {
      expect(mockUpdateUser).toHaveBeenCalledWith({
        avatarFileId: 456,
        username: '新昵称',
      })
    })

    // 验证refreshUser被调用
    await waitFor(() => {
      expect(mockRefreshUser).toHaveBeenCalled()
    })
  })
})