/* @vitest-environment happy-dom */
/* eslint-disable vue/one-component-per-file */

import type { DmsPermissionResource } from '#/api/x/dms/permission';

import { flushPromises, shallowMount } from '@vue/test-utils';
import { defineComponent, h, unref } from 'vue';

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

import ResourceExplorer from '../ResourceExplorer.vue';

const apiMocks = vi.hoisted(() => ({
  copyDmsFolder: vi.fn(),
  deleteDmsFolder: vi.fn(),
  getPermissionResourceTree: vi.fn(),
  moveDmsFolder: vi.fn(),
  reorderDmsFolder: vi.fn(),
}));
const messageMocks = vi.hoisted(() => ({
  createConfirm: vi.fn(),
  error: vi.fn(),
  success: vi.fn(),
}));
const modalMocks = vi.hoisted(() => ({
  index: 0,
  openOperationLog: vi.fn(),
  openRenameFolder: vi.fn(),
}));
const previewMocks = vi.hoisted(() => ({ openDmsFilePreview: vi.fn() }));
const tableMocks = vi.hoisted(() => ({ options: undefined as any }));

vi.mock('#/api/x/dms/permission', () => ({
  copyDmsFolder: apiMocks.copyDmsFolder,
  deleteDmsFolder: apiMocks.deleteDmsFolder,
  getPermissionResourceTree: apiMocks.getPermissionResourceTree,
  moveDmsFolder: apiMocks.moveDmsFolder,
  reorderDmsFolder: apiMocks.reorderDmsFolder,
}));
vi.mock('#/utils/jnpf', () => ({ onlineUtils: { sign: vi.fn() } }));
vi.mock('@jnpf/hooks', () => ({
  useMessage: () => ({
    createConfirm: messageMocks.createConfirm,
    createMessage: messageMocks,
  }),
}));
vi.mock('@jnpf/ui', () => ({ BasicTree: { name: 'BasicTree', template: '<div />' } }));
vi.mock('@jnpf/ui/modal', () => ({
  useModal: () => {
    const openModal = modalMocks.index++ === 0 ? modalMocks.openRenameFolder : modalMocks.openOperationLog;
    return [vi.fn(), { openModal }];
  },
}));
vi.mock('@jnpf/ui/vxeTable', () => ({
  BasicVxeTable: { name: 'BasicVxeTable', template: '<div />' },
  TableAction: { name: 'TableAction', template: '<div />' },
  useVxeTable: (options: any) => {
    tableMocks.options = options;
    return [vi.fn(), {}];
  },
}));
vi.mock('@jnpf/utils', async (importOriginal) => ({
  ...(await importOriginal<typeof import('@jnpf/utils')>()),
  formatToDateTime: (value: string) => value,
}));
vi.mock('../../shared/dmsFilePreview', () => ({
  dmsPreviewErrorMessage: () => '文件预览失败',
  openDmsFilePreview: previewMocks.openDmsFilePreview,
}));
vi.mock('../../file-center/FileOperationLogModal.vue', () => ({ default: { name: 'FileOperationLogModal', template: '<div />' } }));
vi.mock('../RenameFolderModal.vue', () => ({ default: { name: 'RenameFolderModal', template: '<div />' } }));

const BasicTreeStub = defineComponent({
  name: 'BasicTree',
  inheritAttrs: false,
  props: {
    beforeRightClick: { default: undefined, type: Function },
    expandedKeys: { default: () => [], type: Array },
    selectedKeys: { default: () => [], type: Array },
    treeData: { default: () => [], type: Array },
  },
  setup: () => () => h('div', { class: 'basic-tree' }),
});

const BasicVxeTableStub = defineComponent({
  name: 'BasicVxeTable',
  inheritAttrs: false,
  emits: ['cell-click', 'cell-dblclick', 'register'],
  setup(_, { emit, slots }) {
    return () => {
      const rows = (unref(tableMocks.options?.dataSource) || []) as DmsPermissionResource[];
      return h(
        'div',
        { class: 'basic-vxe-table' },
        rows.map((record) =>
          h(
            'div',
            {
              class: 'detail-table-row',
              'data-id': record.id,
              onClick: () => emit('cell-click', { row: record }),
              onDblclick: () => emit('cell-dblclick', { row: record }),
            },
            [slots.entryName?.({ record }), slots.action?.({ record })],
          ),
        ),
      );
    };
  },
});

const TableActionStub = defineComponent({
  name: 'TableAction',
  inheritAttrs: false,
  props: {
    actions: { default: () => [], type: Array },
    stopButtonPropagation: Boolean,
  },
  setup(props) {
    return () =>
      h(
        'div',
        { class: 'table-action' },
        props.actions.map((action: any) =>
          h(
            'button',
            {
              onClick: (event: MouseEvent) => {
                if (props.stopButtonPropagation) event.stopPropagation();
                action.onClick?.();
              },
              type: 'button',
            },
            action.label,
          ),
        ),
      );
  },
});

const rootFolder: DmsPermissionResource = {
  createdAt: '2026-09-01T00:00:00Z',
  id: 'root-folder',
  name: '质量文件',
  resourceType: 'FOLDER',
  revision: 1,
  sourceId: 'root-folder',
  sourceType: 'SYSTEM',
};
const childFolder: DmsPermissionResource = {
  createdAt: '2026-09-02T00:00:00Z',
  id: 'child-folder',
  name: '受控文件',
  parentId: rootFolder.id,
  resourceType: 'FOLDER',
  revision: 1,
  sourceId: 'child-folder',
  sourceType: 'MANUAL',
};
const fileVersion: DmsPermissionResource = {
  createdAt: '2026-09-03T00:00:00Z',
  fileName: '检验规程.pdf',
  id: 'file-version',
  name: '检验规程.pdf',
  parentId: rootFolder.id,
  resourceType: 'FILE_VERSION',
  sourceId: 'file-version',
  sourceType: 'UPLOAD',
  versionNo: 2,
};

async function mountExplorer() {
  const wrapper = shallowMount(ResourceExplorer, {
    global: {
      directives: { loading: {} },
      stubs: {
        'a-button': true,
        'a-button-group': true,
        'a-tooltip': true,
        'jnpf-empty': true,
        'jnpf-input': true,
        BasicTree: BasicTreeStub,
        BasicVxeTable: BasicVxeTableStub,
        FileOperationLogModal: true,
        RenameFolderModal: true,
        TableAction: TableActionStub,
      },
    },
  });
  await flushPromises();
  return wrapper;
}

beforeEach(() => {
  vi.clearAllMocks();
  modalMocks.index = 0;
  tableMocks.options = undefined;
  apiMocks.getPermissionResourceTree.mockImplementation(({ parentId }: { parentId?: string }) => {
    if (!parentId) return Promise.resolve({ data: [rootFolder] });
    if (parentId === rootFolder.id) return Promise.resolve({ data: [childFolder, fileVersion] });
    return Promise.resolve({ data: [] });
  });
  previewMocks.openDmsFilePreview.mockResolvedValue(undefined);
});

afterEach(() => {
  vi.useRealTimers();
});

describe('permission resource explorer standard components', () => {
  it('returns the complete folder context menu through BasicTree', async () => {
    const wrapper = await mountExplorer();
    const tree = wrapper.getComponent(BasicTreeStub);
    const beforeRightClick = tree.props('beforeRightClick') as (node: { key: string }, event: MouseEvent) => Array<{ disabled?: boolean; label: string }>;

    const menu = beforeRightClick({ key: rootFolder.id }, new MouseEvent('contextmenu'));

    expect(menu.map((item) => item.label)).toEqual(['新增', '修改', '删除', '上移', '下移', '剪切', '复制', '粘贴', '刷新']);
    expect(menu.find((item) => item.label === '删除')?.disabled).toBe(true);
    expect(menu.find((item) => item.label === '剪切')?.disabled).toBe(true);
    wrapper.unmount();
  });

  it('keeps delayed cell selection and double-click preview behavior', async () => {
    vi.useFakeTimers();
    const wrapper = await mountExplorer();
    const row = wrapper.get('[data-id="file-version"]');

    await row.trigger('click');
    vi.advanceTimersByTime(250);
    await flushPromises();
    expect(wrapper.emitted('select')?.at(-1)?.[0]).toMatchObject({ id: fileVersion.id });

    await row.trigger('dblclick');
    await flushPromises();
    expect(previewMocks.openDmsFilePreview).toHaveBeenCalledWith({
      fileName: fileVersion.fileName,
      resourceId: fileVersion.id,
      resourceType: 'FILE_VERSION',
    });
    wrapper.unmount();
  });

  it('keeps operation clicks and double-clicks from opening the resource', async () => {
    vi.useFakeTimers();
    const wrapper = await mountExplorer();
    const table = wrapper.getComponent(BasicVxeTableStub);

    await wrapper.get('[data-id="file-version"] .table-action button').trigger('click');
    vi.runAllTimers();
    await flushPromises();

    expect(modalMocks.openOperationLog).toHaveBeenCalledWith(true, { item: fileVersion });
    expect(previewMocks.openDmsFilePreview).not.toHaveBeenCalled();
    expect(wrapper.emitted('select')?.at(-1)?.[0]).toMatchObject({ id: fileVersion.id });

    table.vm.$emit('cell-dblclick', { column: { field: 'action' }, row: fileVersion });
    table.vm.$emit('cell-dblclick', { column: { property: 'action' }, row: fileVersion });
    await wrapper.get('[data-id="file-version"] .entry-action').trigger('dblclick');
    await flushPromises();

    expect(previewMocks.openDmsFilePreview).not.toHaveBeenCalled();
    wrapper.unmount();
  });
});
