import React from 'react'
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import AddressEditPage from '@/pages/address-edit/index'

// 导入Taro mock函数
import { mockUseRouter, mockNavigateBack, mockShowToast } from '~/__mocks__/taroMock'

// Mock API client
jest.mock('@/api', () => ({
  deliveryAddressClient: {
    $post: jest.fn(),
    ':id': {
      $get: jest.fn(),
      $put: jest.fn(),
    },
  },
}))

// Mock auth hook
jest.mock('@/utils/auth', () => ({
  useAuth: () => ({
    user: { id: 1 },
  }),
}))

// Mock react-hook-form
let mockFormData = {
  name: '',
  phone: '',
  province: undefined as number | undefined,
  city: undefined as number | undefined,
  district: undefined as number | undefined,
  town: undefined as number | undefined,
  address: '',
  isDefault: false
}

const mockHandleSubmit = jest.fn((onSubmit, onError) => (e: any) => {
  e?.preventDefault?.()
  // 模拟验证通过，调用onSubmit
  onSubmit(mockFormData)
})

const mockReset = jest.fn((data: any) => {
  if (data) {
    mockFormData = { ...mockFormData, ...data }
  }
})

const mockSetValue = jest.fn((name: string, value: any) => {
  mockFormData = { ...mockFormData, [name]: value }
})

const mockWatch = jest.fn()

jest.mock('react-hook-form', () => ({
  useForm: () => ({
    formState: {
      isValid: true,
      errors: {},
    },
    handleSubmit: mockHandleSubmit,
    reset: mockReset,
    setValue: mockSetValue,
    watch: mockWatch,
    getValues: () => mockFormData,
  }),
}))

// Mock components
jest.mock('@/components/ui/navbar', () => ({
  Navbar: ({ title, onClickLeft }: { title: string; onClickLeft: () => void }) => (
    <div data-testid="navbar">
      <span>{title}</span>
      <button onClick={onClickLeft}>返回</button>
    </div>
  ),
}))

jest.mock('@/components/ui/button', () => ({
  Button: ({ children, onClick, disabled, className }: any) => (
    <button
      onClick={onClick}
      disabled={disabled}
      className={className}
      data-testid="button"
    >
      {children}
    </button>
  ),
}))

jest.mock('@/components/ui/card', () => ({
  Card: ({ children, className }: any) => (
    <div className={className} data-testid="card">
      {children}
    </div>
  ),
}))

jest.mock('@/components/ui/form', () => ({
  Form: ({ children, ...props }: any) => (
    <form {...props} data-testid="form">
      {children}
    </form>
  ),
  FormField: ({ name, render }: any) => (
    <div data-testid={`form-field-${name}`}>
      {render({ field: { value: '', onChange: jest.fn() } })}
    </div>
  ),
  FormItem: ({ children }: any) => <div data-testid="form-item">{children}</div>,
  FormLabel: ({ children }: any) => <label data-testid="form-label">{children}</label>,
  FormControl: ({ children }: any) => <div data-testid="form-control">{children}</div>,
  FormMessage: () => <div data-testid="form-message">错误消息</div>,
}))

jest.mock('@/components/ui/input', () => ({
  Input: ({ placeholder, ...props }: any) => (
    <input
      placeholder={placeholder}
      {...props}
      data-testid="input"
    />
  ),
}))

jest.mock('@/components/ui/switch', () => ({
  Switch: ({ checked, onChange, color }: any) => (
    <input
      type="checkbox"
      checked={checked}
      onChange={onChange}
      data-testid="switch"
      style={{ color }}
    />
  ),
}))

jest.mock('@/components/ui/city-selector', () => ({
  CitySelector: ({
    provinceValue,
    cityValue,
    districtValue,
    townValue,
    onProvinceChange,
    onCityChange,
    onDistrictChange,
    onTownChange,
    showLabels
  }: any) => (
    <div data-testid="city-selector">
      <div>省份: {provinceValue}</div>
      <div>城市: {cityValue}</div>
      <div>区县: {districtValue}</div>
      <div>乡镇: {townValue}</div>
    </div>
  ),
}))

describe('AddressEditPage', () => {
  let queryClient: QueryClient

  beforeEach(() => {
    queryClient = new QueryClient({
      defaultOptions: {
        queries: { retry: false },
        mutations: { retry: false },
      },
    })

    // Reset all mocks
    jest.clearAllMocks()

    // 重置表单数据
    mockFormData = {
      name: '',
      phone: '',
      province: undefined,
      city: undefined,
      district: undefined,
      town: undefined,
      address: '',
      isDefault: false
    }

    // 默认设置无地址ID（添加模式）
    mockUseRouter.mockReturnValue({
      params: {},
    })
  })

  const renderWithProviders = (component: React.ReactElement) => {
    return render(
      <QueryClientProvider client={queryClient}>
        {component}
      </QueryClientProvider>
    )
  }

  const mockAddress = {
    id: 1,
    name: '张三',
    phone: '13812345678',
    receiverProvince: 440000,
    receiverCity: 440300,
    receiverDistrict: 440305,
    receiverTown: 440305001,
    address: '科技大厦A座',
    isDefault: 1,
  }

  it('渲染添加地址页面标题和布局', async () => {
    renderWithProviders(<AddressEditPage />)

    expect(screen.getByTestId('navbar')).toBeInTheDocument()
    expect(screen.getByText('添加地址')).toBeInTheDocument()
    expect(screen.getByTestId('form')).toBeInTheDocument()
  })

  it('渲染编辑地址页面标题和布局', async () => {
    const { deliveryAddressClient } = await import('@/api')
    ;(deliveryAddressClient[':id'].$get as jest.Mock).mockResolvedValue({
      status: 200,
      json: async () => mockAddress,
    } as any)

    mockUseRouter.mockReturnValue({
      params: { id: '1' },
    })

    renderWithProviders(<AddressEditPage />)

    await waitFor(() => {
      expect(screen.getByText('编辑地址')).toBeInTheDocument()
      expect(deliveryAddressClient[':id'].$get).toHaveBeenCalledWith({
        param: { id: 1 }
      })
    })
  })

  it('填充编辑模式下的表单数据', async () => {
    const { deliveryAddressClient } = await import('@/api')
    ;(deliveryAddressClient[':id'].$get as jest.Mock).mockResolvedValue({
      status: 200,
      json: async () => mockAddress,
    } as any)

    mockUseRouter.mockReturnValue({
      params: { id: '1' },
    })

    renderWithProviders(<AddressEditPage />)

    await waitFor(() => {
      expect(deliveryAddressClient[':id'].$get).toHaveBeenCalledWith({
        param: { id: 1 }
      })
    })
  })

  it('提交新建地址表单', async () => {
    const { deliveryAddressClient } = await import('@/api')
    const mockResponse = { id: 2, ...mockAddress, isDefault: 0 }
    ;(deliveryAddressClient.$post as jest.Mock).mockResolvedValue({
      status: 201,
      json: async () => mockResponse,
    } as any)

    renderWithProviders(<AddressEditPage />)

    // 找到保存按钮并点击
    await waitFor(() => {
      const saveButton = screen.getByText('保存地址')
      expect(saveButton).toBeInTheDocument()

      fireEvent.click(saveButton)
    })

    await waitFor(() => {
      expect(deliveryAddressClient.$post).toHaveBeenCalled()
      expect(mockShowToast).toHaveBeenCalledWith({
        title: '添加成功',
        icon: 'success'
      })
      expect(mockNavigateBack).toHaveBeenCalled()
    })
  })

  it('提交编辑地址表单', async () => {
    const { deliveryAddressClient } = await import('@/api')
    ;(deliveryAddressClient[':id'].$get as jest.Mock).mockResolvedValue({
      status: 200,
      json: async () => mockAddress,
    } as any)

    const updatedAddress = { ...mockAddress, name: '李四' }
    ;(deliveryAddressClient[':id'].$put as jest.Mock).mockResolvedValue({
      status: 200,
      json: async () => updatedAddress,
    } as any)

    mockUseRouter.mockReturnValue({
      params: { id: '1' },
    })

    renderWithProviders(<AddressEditPage />)

    // 等待数据加载
    await waitFor(() => {
      expect(deliveryAddressClient[':id'].$get).toHaveBeenCalled()
    })

    // 确保表单已重置
    await waitFor(() => {
      expect(mockReset).toHaveBeenCalled()
    })

    // 找到保存按钮并点击
    await waitFor(() => {
      const saveButton = screen.getByText('保存地址')
      expect(saveButton).toBeInTheDocument()

      fireEvent.click(saveButton)
    })

    await waitFor(() => {
      expect(deliveryAddressClient[':id'].$put).toHaveBeenCalled()
      // 检查调用参数
      const call = deliveryAddressClient[':id'].$put.mock.calls[0]
      expect(call[0]).toEqual(expect.objectContaining({
        param: { id: 1 }
      }))
      expect(mockShowToast).toHaveBeenCalledWith({
        title: '更新成功',
        icon: 'success'
      })
      expect(mockNavigateBack).toHaveBeenCalled()
    })
  })

  it('显示API错误提示', async () => {
    const { deliveryAddressClient } = await import('@/api')
    ;(deliveryAddressClient.$post as jest.Mock).mockResolvedValue({
      status: 400,
      json: async () => ({ message: '保存失败' }),
    } as any)

    renderWithProviders(<AddressEditPage />)

    // 找到保存按钮并点击
    await waitFor(() => {
      const saveButton = screen.getByText('保存地址')
      fireEvent.click(saveButton)
    })

    await waitFor(() => {
      expect(mockShowToast).toHaveBeenCalledWith({
        title: '保存地址失败',
        icon: 'none'
      })
    })
  })

  it('验证表单字段渲染', async () => {
    renderWithProviders(<AddressEditPage />)

    expect(screen.getByText('收货人姓名')).toBeInTheDocument()
    expect(screen.getByText('手机号码')).toBeInTheDocument()
    expect(screen.getByText('详细地址')).toBeInTheDocument()
    expect(screen.getByText('设为默认地址')).toBeInTheDocument()
  })

  it('点击返回按钮', async () => {
    renderWithProviders(<AddressEditPage />)

    const navbar = screen.getByTestId('navbar')
    const backButton = navbar.querySelector('button')

    if (backButton) {
      fireEvent.click(backButton)
      expect(mockNavigateBack).toHaveBeenCalled()
    }
  })

  it('显示保存中的加载状态', async () => {
    const { deliveryAddressClient } = await import('@/api')
    let resolvePromise: any
    const promise = new Promise(resolve => {
      resolvePromise = resolve
    })
    ;(deliveryAddressClient.$post as jest.Mock).mockReturnValue(promise)

    renderWithProviders(<AddressEditPage />)

    // 点击保存按钮
    await waitFor(() => {
      const saveButton = screen.getByText('保存地址')
      fireEvent.click(saveButton)
    })

    // 应该显示加载状态
    await waitFor(() => {
      expect(screen.getByText('保存中...')).toBeInTheDocument()
    })

    // 解析promise
    resolvePromise({
      status: 201,
      json: async () => ({ id: 1 }),
    })

    await waitFor(() => {
      expect(screen.getByText('保存地址')).toBeInTheDocument()
    })
  })
})