import { render, fireEvent, waitFor } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { mockShowModal, mockShowToast, mockGetNetworkType, mockGetEnv } from '~/__mocks__/taroMock'
import OrderButtonBar from '@/components/order/OrderButtonBar'


// Mock API client
jest.mock('@/api', () => ({
  orderClient: {
    cancelOrder: {
      $post: jest.fn()
    }
  }
}))

// Mock CancelReasonDialog 组件
jest.mock('@/components/common/CancelReasonDialog', () => {
  const React = require('react')
  const MockCancelReasonDialog = ({ open, onOpenChange, onConfirm, loading }: any) => {
    const [reason, setReason] = React.useState('')
    const [error, setError] = React.useState('')

    if (!open) return null

    const handleConfirm = () => {
      const trimmedReason = reason.trim()
      if (!trimmedReason) {
        setError('请输入取消原因')
        return
      }
      if (trimmedReason.length < 5) {
        setError('取消原因至少需要5个字符')
        return
      }
      if (trimmedReason.length > 200) {
        setError('取消原因不能超过200个字符')
        return
      }
      setError('')
      onConfirm(trimmedReason)
    }

    // 预定义原因选项
    const CANCEL_REASONS = [
      '我不想买了',
      '信息填写错误，重新下单',
      '商家缺货',
      '价格不合适',
      '其他原因'
    ]

    return React.createElement('div', { 'data-testid': 'cancel-reason-dialog' }, [
      React.createElement('div', { key: 'title' }, '取消订单'),
      React.createElement('div', { key: 'description' }, '请选择或填写取消原因，这将帮助我们改进服务'),
      // 预定义原因选项
      React.createElement('div', { key: 'reasons' },
        CANCEL_REASONS.map((reasonText, index) =>
          React.createElement('div', {
            key: index,
            onClick: () => {
              setReason(reasonText)
              if (error) setError('')
            }
          }, reasonText)
        )
      ),
      React.createElement('input', {
        key: 'reason-input',
        placeholder: '请输入其他取消原因...',
        value: reason,
        onChange: (e: any) => {
          setReason(e.target.value)
          if (error) setError('')
        }
      }),
      error && React.createElement('div', { key: 'error', 'data-testid': 'error-message' }, error),
      React.createElement('button', {
        key: 'confirm',
        onClick: handleConfirm,
        disabled: loading
      }, loading ? '提交中...' : '确认取消'),
      React.createElement('button', {
        key: 'cancel',
        onClick: () => onOpenChange(false)
      }, '取消')
    ])
  }
  MockCancelReasonDialog.displayName = 'MockCancelReasonDialog'
  return MockCancelReasonDialog
})

const mockOrder = {
  id: 1,
  orderNo: 'ORDER001',
  payState: 0, // 未支付
  state: 0, // 未发货
  amount: 100,
  payAmount: 100,
  freightAmount: 0,
  discountAmount: 0,
  goodsDetail: JSON.stringify([
    { id: 1, name: '商品1', price: 50, num: 2, image: '', spec: '默认规格' }
  ]),
  recevierName: '张三',
  receiverMobile: '13800138000',
  address: '北京市朝阳区',
  createdAt: '2025-01-01T00:00:00Z'
}

const createTestQueryClient = () => new QueryClient({
  defaultOptions: {
    queries: { retry: false },
    mutations: { retry: false }
  }
})

const TestWrapper = ({ children }: { children: React.ReactNode }) => (
  <QueryClientProvider client={createTestQueryClient()}>
    {children}
  </QueryClientProvider>
)

describe('OrderButtonBar', () => {
  beforeEach(() => {
    jest.clearAllMocks()
    // 模拟网络检查成功回调
    mockGetNetworkType.mockImplementation((options) => {
      if (options?.success) {
        options.success({ networkType: 'wifi' })
      }
      return Promise.resolve()
    })
    // 模拟环境检查
    mockGetEnv.mockReturnValue('WEB')
  })

  it('should render cancel button for unpaid order', () => {
    const { getByText } = render(
      <TestWrapper>
        <OrderButtonBar order={mockOrder} onViewDetail={jest.fn()} />
      </TestWrapper>
    )

    expect(getByText('取消订单')).toBeTruthy()
    expect(getByText('去支付')).toBeTruthy()
    expect(getByText('查看详情')).toBeTruthy()
  })

  it('should show cancel reason dialog when cancel button is clicked', async () => {
    const { getByText, getByTestId } = render(
      <TestWrapper>
        <OrderButtonBar order={mockOrder} onViewDetail={jest.fn()} />
      </TestWrapper>
    )

    fireEvent.click(getByText('取消订单'))

    await waitFor(() => {
      expect(getByTestId('cancel-reason-dialog')).toBeTruthy()
      // 检查对话框内容
      expect(getByText('请选择或填写取消原因，这将帮助我们改进服务')).toBeTruthy()
    })
  })

  it('should call API when cancel order is confirmed', async () => {
    const mockApiCall = require('@/api').orderClient.cancelOrder.$post as jest.Mock

    mockShowModal.mockResolvedValueOnce({ confirm: true }) // 确认取消

    mockApiCall.mockResolvedValue({ status: 200, json: () => Promise.resolve({ success: true, message: '取消成功' }) })

    const { getByText, getByPlaceholderText, getByTestId } = render(
      <TestWrapper>
        <OrderButtonBar order={mockOrder} onViewDetail={jest.fn()} />
      </TestWrapper>
    )

    // 打开取消对话框
    fireEvent.click(getByText('取消订单'))

    await waitFor(() => {
      expect(getByTestId('cancel-reason-dialog')).toBeTruthy()
    })

    // 输入取消原因
    const reasonInput = getByPlaceholderText('请输入其他取消原因...')
    fireEvent.change(reasonInput, { target: { value: '测试取消原因' } })

    // 点击确认取消按钮
    fireEvent.click(getByText('确认取消'))

    await waitFor(() => {
      expect(mockShowModal).toHaveBeenCalledWith({
        title: '确认取消',
        content: '确定要取消订单吗？\n取消原因：测试取消原因',
        success: expect.any(Function)
      })
    })

    // 模拟确认对话框确认
    const modalCall = mockShowModal.mock.calls[0][0]
    if (modalCall.success) {
      modalCall.success({ confirm: true })
    }

    await waitFor(() => {
      expect(mockApiCall).toHaveBeenCalledWith({
        json: {
          orderId: 1,
          reason: '测试取消原因'
        }
      })
    })
  })

  it('should show error when cancel reason is empty', async () => {
    const { getByText, getByTestId } = render(
      <TestWrapper>
        <OrderButtonBar order={mockOrder} onViewDetail={jest.fn()} />
      </TestWrapper>
    )

    // 打开取消对话框
    fireEvent.click(getByText('取消订单'))

    await waitFor(() => {
      expect(getByTestId('cancel-reason-dialog')).toBeTruthy()
    })

    // 直接点击确认取消按钮（不输入原因）
    fireEvent.click(getByText('确认取消'))

    await waitFor(() => {
      expect(getByTestId('error-message')).toBeTruthy()
      expect(getByText('请输入取消原因')).toBeTruthy()
    })
  })

  it('should handle network error gracefully', async () => {
    const mockApiCall = require('@/api').orderClient.cancelOrder.$post as jest.Mock

    mockShowModal.mockResolvedValueOnce({ confirm: true })

    mockApiCall.mockRejectedValue(new Error('网络连接失败'))

    const { getByText, getByPlaceholderText, getByTestId } = render(
      <TestWrapper>
        <OrderButtonBar order={mockOrder} onViewDetail={jest.fn()} />
      </TestWrapper>
    )

    // 打开取消对话框
    fireEvent.click(getByText('取消订单'))

    await waitFor(() => {
      expect(getByTestId('cancel-reason-dialog')).toBeTruthy()
    })

    // 输入取消原因
    const reasonInput = getByPlaceholderText('请输入其他取消原因...')
    fireEvent.change(reasonInput, { target: { value: '测试取消原因' } })

    // 点击确认取消按钮
    fireEvent.click(getByText('确认取消'))

    // 模拟确认对话框确认
    await waitFor(() => {
      expect(mockShowModal).toHaveBeenCalledWith({
        title: '确认取消',
        content: '确定要取消订单吗？\n取消原因：测试取消原因',
        success: expect.any(Function)
      })
    })

    const modalCall = mockShowModal.mock.calls[0][0]
    if (modalCall.success) {
      modalCall.success({ confirm: true })
    }

    await waitFor(() => {
      expect(mockShowToast).toHaveBeenCalledWith({
        title: '网络连接失败，请检查网络后重试',
        icon: 'error',
        duration: 3000
      })
    })
  })

  it('should disable cancel button during mutation', async () => {
    // 模拟mutation正在进行中
    const mockApiCall = require('@/api').orderClient.cancelOrder.$post as jest.Mock
    mockApiCall.mockImplementation(() => new Promise(() => {})) // 永不resolve的promise

    const { getByText, getByPlaceholderText, getByTestId } = render(
      <TestWrapper>
        <OrderButtonBar order={mockOrder} onViewDetail={jest.fn()} />
      </TestWrapper>
    )

    // 打开取消对话框
    fireEvent.click(getByText('取消订单'))

    await waitFor(() => {
      expect(getByTestId('cancel-reason-dialog')).toBeTruthy()
    })

    // 输入取消原因
    const reasonInput = getByPlaceholderText('请输入其他取消原因...')
    fireEvent.change(reasonInput, { target: { value: '测试取消原因' } })

    // 点击确认取消按钮
    fireEvent.click(getByText('确认取消'))

    // 模拟确认对话框确认
    await waitFor(() => {
      expect(mockShowModal).toHaveBeenCalledWith({
        title: '确认取消',
        content: '确定要取消订单吗？\n取消原因：测试取消原因',
        success: expect.any(Function)
      })
    })

    const modalCall = mockShowModal.mock.calls[0][0]
    if (modalCall.success) {
      modalCall.success({ confirm: true })
    }

    // 检查按钮状态
    await waitFor(() => {
      expect(getByText('取消中...')).toBeTruthy()
    })
  })

  it('should not show cancel button for shipped order', () => {
    const shippedOrder = {
      ...mockOrder,
      payState: 2, // 已支付
      state: 1     // 已发货
    }

    const { queryByText } = render(
      <TestWrapper>
        <OrderButtonBar order={shippedOrder} onViewDetail={jest.fn()} />
      </TestWrapper>
    )

    expect(queryByText('取消订单')).toBeNull()
    expect(queryByText('确认收货')).toBeTruthy()
  })

  it('should use external cancel handler when provided', async () => {
    const mockOnCancelOrder = jest.fn()

    const { getByText } = render(
      <TestWrapper>
        <OrderButtonBar
          order={mockOrder}
          onViewDetail={jest.fn()}
          onCancelOrder={mockOnCancelOrder}
        />
      </TestWrapper>
    )

    fireEvent.click(getByText('取消订单'))

    await waitFor(() => {
      expect(mockOnCancelOrder).toHaveBeenCalled()
    })
  })
})