import { nextTick } from 'vue'
import { shallowMount, mount } from '@vue/test-utils'

import TreeComponent from '@vue2-client/base-client/components/common/Tree'
import * as CommonApi from '@vue2-client/services/api/common'
import { afterEach, beforeEach, describe, expect, it, jest } from '@jest/globals'

function handleLogic (logicName, parameters) {
  // 使用 switch 语句来处理多种业务逻辑
  switch (logicName) {
    case 'get_root_nodes':
      // 返回特定于 'get_root_nodes' 业务逻辑的数据
      return Promise.resolve({
        data: [{
          key: '0-0',
children: [],
          title: '某某燃气有限公司',
        }],
      })

    case 'get_child_nodes':
      // 根据 'another_logic' 执行不同的操作
      // ...（执行相关操作）
      return Promise.resolve({
        data: [
          { id: '2' },
        ],
      })

    // ...您可以添加更多的 case 语句来处理更多的业务逻辑

    default:
      // 如果传入了一个未处理的业务逻辑名称，您可以有一个默认的行为或返回一个错误。
      return Promise.reject(new Error('未知的业务逻辑名称: ' + logicName))
  }
}

describe('TreeComponent', () => {
  let runLogicSpy // 将变量声明移动到这里，使其在下面的作用域中可见
  let wrapper

  beforeEach(() => {
    // 这里，我们使用 'spyOn' 只拦截 'runLogic' 函数，而不影响模块中的其他函数
    runLogicSpy = jest.spyOn(CommonApi, 'runLogic')
    // 现在，你可以定义这个函数的模拟实现或返回值
    runLogicSpy.mockImplementation((logicName, parameters) => {
      return handleLogic(logicName, parameters) // 这里是你的模拟实现)
    })

    // 在这里，我们通过 propsData 传递 prop
    wrapper = mount(TreeComponent, {
      propsData: {
        configContent: {}, // 这里添加你的配置内容
        // ... 如果还有其他 props，也在这里添加 ...
      },
    })
  })

  afterEach(() => {
    // 测试之后，你应该清理模拟，以确保它不会影响其他测试
    runLogicSpy.mockRestore()
    wrapper.destroy()
  })

  it('renders a Tree component', () => {
    expect(wrapper.findComponent({ name: 'a-tree' }).exists()).toBe(true)
  })

  it('calls generateTreeData method on mounted', async () => {
  // 首先创建spy
    const generateTreeData = jest.spyOn(TreeComponent.methods, 'generateTreeData')

    // 挂载组件，并通过 propsData 传递参数
    wrapper = await mount(TreeComponent, {
      propsData: {
        configContent: {}, // 这里添加实际的配置内容
        // ...如果还有其他props，也可以在这里添加...
      },
    })

    // 现在检查 generateTreeData 是否已被调用
    expect(generateTreeData).toHaveBeenCalled()
  })

  it('generates treeData correctly', () => {
    const expectedTreeData =
      [{
        key: '0-0',
children: [],
        title: '某某燃气有限公司',
    }]

    expect(wrapper.vm.treeData).toEqual(expectedTreeData)
  })

  it('expands a node and fetches child nodes correctly', async () => {
    // 准备一些模拟数据
    const mockNode = {
      id: '1', // 或其他唯一标识符
      children: [], // 初始时假设没有子节点
    }

    const mockChildren = [
      { id: '2', parentNode: mockNode },
      // ...更多子节点
    ]

    // 准备handleExpand方法所需的参数
    const expandedKeys = ['1'] // 假设这是当前展开的节点keys
    const info = {
      expanded: true, // 假设节点是被展开的
      node: mockNode, // 当前操作的节点
    }

    // 现在调用handleExpand方法
    await wrapper.vm.handleExpand(expandedKeys, info)

    // 我们还期望mockNode的子节点被更新
    expect(mockNode.children).toEqual(mockChildren)

    // 如果handleExpand方法更新了expandedKeys数组，我们也要验证这一点
    const expectedExpandedKeys = ['1'] // 假设它应该包含被展开节点的id
    expect(wrapper.vm.expandedKeys).toEqual(expectedExpandedKeys)
  })

  it('selects a node and emits nodeSelected event correctly', () => {
    // 准备 mock 数据
    const mockNode = { title: '某某燃气有限公司', parentNode: null }
    const selectedKeys = ['1'] // 这个应该基于 mockNode 的数据
    const selectInfo = { selected: true, node: mockNode }

    // 调用 handleSelect 方法
    wrapper.vm.handleSelect(selectedKeys, selectInfo)

    // 断言已发出正确的事件
    const emittedEvents = wrapper.emitted('nodeSelected')
    expect(emittedEvents).toBeTruthy() // 确认是否有事件被发出
    expect(emittedEvents).toHaveLength(1) // 只有一个事件被发出
    expect(emittedEvents[0]).toEqual(['某某燃气有限公司']) // 传出的事件携带了正确的数据

    // 如果 handleSelect 方法更改了内部状态（例如，'selectedKeys'），也要进行断言
    expect(wrapper.vm.selectedKeys).toEqual([])
  })

  it('expands a node when clicked', async () => {
    console.log(wrapper.html()) // 打印组件的 HTML 输出

    // 找到 role 为 "treeitem" 的元素，这代表树节点
    const treeNode = wrapper.find('li[role="treeitem"]')

    // 确认我们找到了节点
    expect(treeNode.exists()).toBe(true)

    // 模拟用户点击，展开节点
    await treeNode.trigger('click')

    // 必须等待 nextTick 以便 Vue 更新 DOM
    await nextTick()

    // 现在检查是否更新了 expandedKeys
    expect(wrapper.vm.expandedKeys).toContain('0-0') // 假设 '0-0' 是被点击的节点的 key

    // 检查 'expand' 事件是否被正确触发
    const expandEvents = wrapper.emitted('expand')
    expect(expandEvents).toBeTruthy()
    expect(expandEvents.length).toBeGreaterThan(0) // 确认至少触发了一次
  })
})
