import { flushPromises, mount } from '@vue/test-utils'
import { createI18n } from 'vue-i18n'
import { beforeEach, describe, expect, it, vi } from 'vitest'

import zhCN from '@/i18n/locales/zh-CN'
import SystemMenusView from '@/views/system/SystemMenusView.vue'

vi.mock('@/services/systemAdminService', async (importOriginal) => {
  const actual = await importOriginal<typeof import('@/services/systemAdminService')>()
  return {
    ...actual,
    createAdminMenu: vi.fn(),
    fetchAdminMenuTree: vi.fn(),
    fetchAdminPermissions: vi.fn(),
    updateAdminMenu: vi.fn(),
    updateAdminMenuTreeOrder: vi.fn(),
  }
})

const systemAdminService = await import('@/services/systemAdminService')

function createMenuTree(options: { warnings?: string[] } = {}) {
  return {
    items: [
      {
        id: '40001',
        parent_id: null,
        menu_code: 'SYSTEM_SETTINGS',
        menu_name: '系统设置',
        menu_type: 'GROUP',
        route_path: '/system',
        component_key: 'system',
        icon_key: 'pi pi-cog',
        permission_code: 'SYSTEM_ADMIN_CONSOLE_ACCESS',
        sort_order: 900,
        visible: true,
        menu_status: 'ACTIVE',
        known_route: true,
        created_at: '2026-07-16T00:00:00Z',
        updated_at: '2026-07-16T00:00:00Z',
        children: [
          {
            id: '40002',
            parent_id: '40001',
            menu_code: 'SYSTEM_USERS',
            menu_name: '用户管理',
            menu_type: 'PAGE',
            route_path: '/system/users',
            component_key: 'systemUsers',
            icon_key: 'pi pi-users',
            permission_code: 'SYSTEM_USER_MANAGE',
            sort_order: 100,
            visible: true,
            menu_status: 'ACTIVE',
            known_route: true,
            created_at: '2026-07-16T00:00:00Z',
            updated_at: '2026-07-16T00:00:00Z',
            children: [],
          },
          {
            id: '40003',
            parent_id: '40001',
            menu_code: 'SYSTEM_ROLES',
            menu_name: '角色权限',
            menu_type: 'PAGE',
            route_path: '/system/roles',
            component_key: 'systemRoles',
            icon_key: 'pi pi-shield',
            permission_code: 'SYSTEM_ROLE_MANAGE',
            sort_order: 200,
            visible: true,
            menu_status: 'ACTIVE',
            known_route: true,
            created_at: '2026-07-16T00:00:00Z',
            updated_at: '2026-07-16T00:00:00Z',
            children: [],
          },
        ],
      },
      {
        id: '49999',
        parent_id: '48888',
        menu_code: 'BROKEN_MENU',
        menu_name: '孤儿菜单',
        menu_type: 'PAGE',
        route_path: '/ghost',
        component_key: 'ghost',
        icon_key: 'pi pi-question',
        permission_code: null,
        sort_order: 999,
        visible: true,
        menu_status: 'ACTIVE',
        known_route: false,
        created_at: '2026-07-16T00:00:00Z',
        updated_at: '2026-07-16T00:00:00Z',
        children: [],
      },
    ],
    warnings: options.warnings ?? [],
  }
}

function mountSystemMenusView() {
  const i18n = createI18n({
    legacy: false,
    locale: 'zh-CN',
    messages: {
      'zh-CN': zhCN,
    },
  })

  return mount(SystemMenusView, {
    global: {
      plugins: [i18n],
    },
  })
}

describe('SystemMenusView', () => {
  beforeEach(() => {
    vi.mocked(systemAdminService.fetchAdminMenuTree).mockReset()
    vi.mocked(systemAdminService.fetchAdminPermissions).mockReset()
    vi.mocked(systemAdminService.createAdminMenu).mockReset()
    vi.mocked(systemAdminService.updateAdminMenu).mockReset()
    vi.mocked(systemAdminService.updateAdminMenuTreeOrder).mockReset()
    vi.mocked(systemAdminService.fetchAdminPermissions).mockResolvedValue([])
  })

  it('renders the backend menu tree with warning state', async () => {
    vi.mocked(systemAdminService.fetchAdminMenuTree).mockResolvedValue(
      createMenuTree({
        warnings: ['菜单 49999 的 parent_id=48888 不存在，已按根级异常节点返回。'],
      }),
    )

    const wrapper = mountSystemMenusView()
    await flushPromises()

    expect(systemAdminService.fetchAdminMenuTree).toHaveBeenCalledTimes(1)
    expect(wrapper.text()).toContain('系统设置')
    expect(wrapper.text()).toContain('用户管理')
    expect(wrapper.text()).toContain('孤儿菜单')
    expect(wrapper.text()).toContain('菜单树存在异常配置')
    expect(wrapper.find('[data-testid="menu-tree"]').exists()).toBe(true)
  })

  it('saves reordered sibling nodes through tree-order endpoint', async () => {
    vi.mocked(systemAdminService.fetchAdminMenuTree).mockResolvedValue(createMenuTree())
    vi.mocked(systemAdminService.updateAdminMenuTreeOrder).mockResolvedValue({
      items: createMenuTree().items,
      warnings: [],
    })

    const wrapper = mountSystemMenusView()
    await flushPromises()

    const rolesMoveUp = wrapper.find('[data-testid="move-up-40003"]')
    expect(rolesMoveUp.exists()).toBe(true)
    await rolesMoveUp.trigger('click')
    expect(wrapper.text()).toContain('树结构有未保存调整')

    await wrapper.find('[data-testid="save-tree-order"]').trigger('click')
    await flushPromises()

    expect(systemAdminService.updateAdminMenuTreeOrder).toHaveBeenCalledWith({
      items: expect.arrayContaining([
        expect.objectContaining({
          menu_id: '40003',
          parent_id: '40001',
          sort_order: 100,
        }),
        expect.objectContaining({
          menu_id: '40002',
          parent_id: '40001',
          sort_order: 200,
        }),
      ]),
    })
  })

  it('blocks tree refresh and menu config save while tree order has unsaved changes', async () => {
    vi.mocked(systemAdminService.fetchAdminMenuTree).mockResolvedValue(createMenuTree())

    const wrapper = mountSystemMenusView()
    await flushPromises()

    await wrapper.find('[data-testid="move-up-40003"]').trigger('click')

    expect(wrapper.text()).toContain('树结构有未保存调整')
    expect(wrapper.find('[data-testid="refresh-menu-tree"]').attributes('disabled')).toBeDefined()
    expect(wrapper.find('[data-testid="update-menu-config"]').attributes('disabled')).toBeDefined()
  })

  it('keeps the loaded tree visible when tree-order save fails', async () => {
    vi.mocked(systemAdminService.fetchAdminMenuTree).mockResolvedValue(createMenuTree())
    vi.mocked(systemAdminService.updateAdminMenuTreeOrder).mockRejectedValue(new Error('保存树结构失败'))

    const wrapper = mountSystemMenusView()
    await flushPromises()

    await wrapper.find('[data-testid="move-up-40003"]').trigger('click')
    await wrapper.find('[data-testid="save-tree-order"]').trigger('click')
    await flushPromises()

    expect(wrapper.find('[data-testid="menu-tree"]').exists()).toBe(true)
    expect(wrapper.text()).toContain('保存树结构失败')
    expect(wrapper.text()).toContain('用户管理')
  })

  it('shows permission load failure and disables menu config submit', async () => {
    vi.mocked(systemAdminService.fetchAdminMenuTree).mockResolvedValue(createMenuTree())
    vi.mocked(systemAdminService.fetchAdminPermissions).mockRejectedValue(new Error('权限接口异常'))

    const wrapper = mountSystemMenusView()
    await flushPromises()

    expect(wrapper.text()).toContain('权限列表加载失败')
    expect(wrapper.find('[data-testid="update-menu-config"]').attributes('disabled')).toBeDefined()
  })

  it('locks tree ordering when backend returns tree warnings', async () => {
    vi.mocked(systemAdminService.fetchAdminMenuTree).mockResolvedValue(
      createMenuTree({
        warnings: ['菜单 49999 的 parent_id=48888 不存在，已按根级异常节点返回。'],
      }),
    )

    const wrapper = mountSystemMenusView()
    await flushPromises()

    expect(wrapper.find('[data-testid="save-tree-order"]').attributes('disabled')).toBeDefined()
    expect(wrapper.find('[data-testid="move-up-40003"]').attributes('disabled')).toBeDefined()
    expect(wrapper.text()).toContain('请先处理菜单树异常')
  })

  it('clears dragged menu state on dragend before a later tree drop', async () => {
    vi.mocked(systemAdminService.fetchAdminMenuTree).mockResolvedValue(createMenuTree())

    const wrapper = mountSystemMenusView()
    await flushPromises()

    await wrapper.find('[data-testid="menu-row-40002"]').trigger('dragstart')
    await wrapper.find('[data-testid="menu-row-40002"]').trigger('dragend')
    await wrapper.find('[data-testid="menu-tree"]').trigger('drop')

    expect(wrapper.text()).not.toContain('树结构有未保存调整')
  })
})
