/* eslint-disable vue/one-component-per-file -- Inline stubs keep this interaction test isolated. */
import { flushPromises, mount } from '@vue/test-utils';
import { defineComponent, h } from 'vue';

import { beforeEach, describe, expect, it, vi } from 'vitest';

import SysDeptList from './SysDeptList.vue';

const apiMocks = vi.hoisted(() => ({
  get: vi.fn(),
  post: vi.fn(),
}));
const tableMocks = vi.hoisted(() => ({
  clearSelection: vi.fn(),
  toggleRowExpansion: vi.fn(),
}));
const dictStoreMocks = vi.hoisted(() => ({
  fetchDictionary: vi.fn(),
  getDictLabel: vi.fn(),
}));

vi.mock('#/api/request', () => ({ api: apiMocks }));
vi.mock('#/locales', () => ({ $t: (key: string) => key }));
vi.mock('#/store', () => ({ useDictStore: () => dictStoreMocks }));
vi.mock('./SysDeptModal.vue', () => ({
  default: defineComponent({
    name: 'SysDeptModal',
    setup: () => () => h('div'),
  }),
}));
vi.mock('#/components/dict/DictSelect.vue', () => ({
  default: defineComponent({
    name: 'DictSelect',
    setup: () => () => h('div'),
  }),
}));
vi.mock('element-plus', () => ({
  ElButton: defineComponent({
    name: 'ElButton',
    setup(_, { attrs, slots }) {
      return () => h('button', attrs, slots.default?.());
    },
  }),
  ElForm: defineComponent({
    name: 'ElForm',
    setup(_, { expose, slots }) {
      expose({
        resetFields: vi.fn(),
        validate: (callback: (valid: boolean) => void) => callback(true),
      });
      return () => h('form', slots.default?.());
    },
  }),
  ElFormItem: defineComponent({
    name: 'ElFormItem',
    setup(_, { slots }) {
      return () => h('div', slots.default?.());
    },
  }),
  ElIcon: defineComponent({
    name: 'ElIcon',
    setup(_, { slots }) {
      return () => h('span', slots.default?.());
    },
  }),
  ElInput: defineComponent({
    name: 'ElInput',
    inheritAttrs: false,
    props: { modelValue: { default: '', type: String } },
    emits: ['update:modelValue'],
    setup(props, { attrs, emit }) {
      return () =>
        h('input', {
          ...attrs,
          value: props.modelValue,
          onInput: (event: Event) =>
            emit('update:modelValue', (event.target as HTMLInputElement).value),
        });
    },
  }),
  ElMessage: {
    error: vi.fn(),
    success: vi.fn(),
    warning: vi.fn(),
  },
  ElMessageBox: { confirm: vi.fn() },
  ElTable: defineComponent({
    name: 'ElTable',
    setup(_, { expose, slots }) {
      expose(tableMocks);
      return () => h('div', slots.default?.());
    },
  }),
  ElTableColumn: defineComponent({
    name: 'ElTableColumn',
    setup: () => () => h('div'),
  }),
}));

describe('sysDeptList search expansion', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    apiMocks.get.mockResolvedValue({ data: [] });
  });

  it('expands every matched department path after keyword search', async () => {
    const matchedTree = [
      {
        children: [
          {
            children: [{ id: 'matched', deptName: '研发一部' }],
            id: 'branch',
            deptName: '技术部',
          },
        ],
        id: 'root',
        deptName: '总行',
      },
    ];
    const rootDepartment = matchedTree[0];
    const branchDepartment = rootDepartment?.children[0];
    if (!rootDepartment || !branchDepartment) {
      throw new Error('部门搜索测试数据缺少祖先节点');
    }
    apiMocks.get
      .mockResolvedValueOnce({ data: [] })
      .mockResolvedValueOnce({ data: matchedTree });
    const wrapper = mount(SysDeptList, {
      global: {
        directives: {
          access: {},
          loading: {},
        },
      },
    });
    await flushPromises();
    tableMocks.toggleRowExpansion.mockClear();

    const input = wrapper.get('input');
    await input.setValue('  研发  ');
    await input.trigger('keyup', { key: 'Enter' });
    await flushPromises();

    expect(apiMocks.get).toHaveBeenLastCalledWith('/api/v1/sysDept/list', {
      params: {
        asTree: true,
        keyword: '研发',
        status: undefined,
      },
    });
    expect(tableMocks.toggleRowExpansion).toHaveBeenCalledTimes(2);
    expect(tableMocks.toggleRowExpansion).toHaveBeenNthCalledWith(
      1,
      rootDepartment,
      true,
    );
    expect(tableMocks.toggleRowExpansion).toHaveBeenNthCalledWith(
      2,
      branchDepartment,
      true,
    );
    wrapper.unmount();
  });
});
