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

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

import TemplatePage from '../index.vue';
import pageSource from '../index.vue?raw';

const apiMocks = vi.hoisted(() => ({
  getTemplateCategoryTree: vi.fn(),
  getTemplateDirectory: vi.fn(),
}));
const localFormOpenMock = vi.hoisted(() => vi.fn());
const messageMocks = vi.hoisted(() => ({ error: vi.fn(), success: vi.fn(), warning: vi.fn() }));
const formState = vi.hoisted(() => ({ resetFields: vi.fn(), values: {} as Record<string, unknown> }));
const tableState = vi.hoisted(() => ({
  actions: [] as any[],
  config: undefined as any,
  reload: vi.fn(),
  row: {
    bizEnabled: 'enabled',
    bizStatus: 'PUBLISHED',
    mubanBianhao: 'TMP-001',
    shengxiaoMubanBanben: 'R01',
    shengxiaoMubanId: 'template-1',
  } as any,
}));
const modalState = vi.hoisted(() => ({
  opened: [] as Array<{ data?: any; key: string }>,
}));

const ButtonStub = defineComponent({
  name: 'AButton',
  emits: ['click'],
  setup(_, { emit, slots }) {
    return () => h('button', { onClick: () => emit('click'), type: 'button' }, slots.default?.());
  },
});
vi.mock('#/api/x/eln/templates', () => ({
  getTemplateCategoryTree: apiMocks.getTemplateCategoryTree,
  getTemplateDirectory: apiMocks.getTemplateDirectory,
}));

vi.mock('@jnpf/ui', async () => {
  const { defineComponent, h } = await import('vue');
  return {
    BasicLeftTree: defineComponent({
      name: 'BasicLeftTree',
      props: {
        fieldNames: { default: () => ({}), type: Object },
        loading: Boolean,
        showReset: Boolean,
        title: { default: '', type: String },
        treeData: { default: () => [], type: Array },
      },
      emits: ['reload', 'reset', 'select'],
      setup(props) {
        return () => h('div', { 'data-test': 'template-category-tree' }, JSON.stringify(props.treeData));
      },
    }),
  };
});

vi.mock('#/components/GlobalFormModal/index.vue', async () => {
  const { defineComponent, h } = await import('vue');
  return {
    default: defineComponent({
      name: 'GlobalFormModal',
      props: { listenGlobal: Boolean },
      setup(_, { expose }) {
        expose({ open: localFormOpenMock });
        return () => h('div', { 'data-test': 'local-form-modal' });
      },
    }),
  };
});

vi.mock('../VersionDrawer.vue', async () => {
  const { defineComponent, h } = await import('vue');
  return { default: defineComponent({ name: 'VersionDrawer', setup: () => () => h('div') }) };
});

vi.mock('@jnpf/hooks', () => ({
  useMessage: () => ({ createMessage: messageMocks }),
}));

vi.mock('@jnpf/ui/form', () => ({
  BasicForm: { name: 'BasicForm', template: '<div />' },
  useForm: () => [vi.fn(), { getFieldsValue: () => formState.values, resetFields: formState.resetFields }],
}));

vi.mock('@jnpf/ui/drawer', () => ({
  useDrawer: () => [vi.fn(), { openDrawer: (open: boolean, data?: any) => open && modalState.opened.push({ data, key: 'versionList' }) }],
}));

vi.mock('@jnpf/ui/vxeTable', async () => {
  const { defineComponent, h } = await import('vue');
  return {
    BasicVxeTable: defineComponent({
      name: 'BasicVxeTable',
      setup(_, { slots }) {
        return () =>
          h('div', [
            slots.tableTitle?.(),
            slots.jianyanXiangmu?.({ record: tableState.row }),
            slots.mubanFenlei?.({ record: tableState.row }),
            slots.shengxiaoMubanBanben?.({ record: tableState.row }),
            slots.action?.({ record: tableState.row }),
          ]);
      },
    }),
    TableAction: defineComponent({
      name: 'TableAction',
      props: { actions: Array },
      setup(props) {
        tableState.actions = props.actions as any[];
        return () => h('div');
      },
    }),
    useVxeTable: (config: any) => {
      tableState.config = config;
      return [vi.fn(), { reload: tableState.reload }];
    },
  };
});

describe('eLN template page', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    localFormOpenMock.mockResolvedValue(undefined);
    tableState.actions = [];
    tableState.row = {
      bizEnabled: 'enabled',
      bizStatus: 'PUBLISHED',
      mubanBianhao: 'TMP-001',
      shengxiaoMubanBanben: 'R01',
      shengxiaoMubanId: 'template-1',
    };
    modalState.opened = [];
    formState.values = {};
    apiMocks.getTemplateDirectory.mockResolvedValue({ data: { list: [], pagination: { currentPage: 1, pageSize: 20, total: 0 } } });
    apiMocks.getTemplateCategoryTree.mockResolvedValue({ data: [{ f_id: 'category-1', fenlei_mingcheng: '检验记录' }] });
  });

  it('加载电子记录分类树', async () => {
    const wrapper = mount(TemplatePage, {
      global: {
        stubs: {
          'a-button': true,
          'a-form-item': true,
          'a-tag': true,
          'a-textarea': true,
          VersionModal: true,
        },
      },
    });

    await vi.waitFor(() => expect(apiMocks.getTemplateCategoryTree).toHaveBeenCalledOnce());
    const tree = wrapper.findComponent({ name: 'BasicLeftTree' });
    await vi.waitFor(() => expect(tree.props('treeData')).toEqual([{ f_id: 'category-1', fenlei_mingcheng: '检验记录' }]));
    expect(tree.props()).toMatchObject({
      fieldNames: { children: 'children', key: 'f_id', title: 'fenlei_mingcheng' },
      showReset: true,
      title: '电子记录分类',
      treeData: [{ f_id: 'category-1', fenlei_mingcheng: '检验记录' }],
    });
  });

  it('兼容分类树接口返回 JSON 字符串', async () => {
    apiMocks.getTemplateCategoryTree.mockResolvedValueOnce({
      data: JSON.stringify([{ f_id: 'category-2', fenlei_mingcheng: '原始记录' }]),
    });
    const wrapper = mount(TemplatePage, {
      global: {
        stubs: {
          'a-button': true,
          'a-form-item': true,
          'a-tag': true,
          'a-textarea': true,
          VersionModal: true,
        },
      },
    });
    const tree = wrapper.findComponent({ name: 'BasicLeftTree' });

    await vi.waitFor(() => expect(tree.props('treeData')).toEqual([{ f_id: 'category-2', fenlei_mingcheng: '原始记录' }]));
  });

  it('刷新分类树时重新请求分类数据', async () => {
    const wrapper = mount(TemplatePage, {
      global: {
        stubs: {
          'a-button': true,
          'a-form-item': true,
          'a-tag': true,
          'a-textarea': true,
          VersionModal: true,
        },
      },
    });
    const tree = wrapper.findComponent({ name: 'BasicLeftTree' });

    await vi.waitFor(() => expect(apiMocks.getTemplateCategoryTree).toHaveBeenCalledOnce());
    tree.vm.$emit('reload');

    await vi.waitFor(() => expect(apiMocks.getTemplateCategoryTree).toHaveBeenCalledTimes(2));
  });

  it('点击分类后与当前搜索条件组合查询并回到第一页', async () => {
    formState.values = { bizEnabled: 'enabled', bizStatus: 'PUBLISHED', keyword: '无菌' };
    const wrapper = mount(TemplatePage, {
      global: {
        stubs: {
          'a-button': true,
          'a-form-item': true,
          'a-tag': true,
          'a-textarea': true,
          VersionModal: true,
        },
      },
    });

    wrapper.findComponent({ name: 'BasicLeftTree' }).vm.$emit('select', 'category-1');

    expect(tableState.reload).toHaveBeenCalledWith({
      page: 1,
      searchInfo: { bizEnabled: 'enabled', bizStatus: 'PUBLISHED', keyword: '无菌', mubanFenlei: 'category-1' },
    });
  });

  it('重置分类树时清空分类并保留搜索条件', () => {
    formState.values = { bizEnabled: 'enabled', keyword: '无菌' };
    const wrapper = mount(TemplatePage, {
      global: {
        stubs: {
          'a-button': true,
          'a-form-item': true,
          'a-tag': true,
          'a-textarea': true,
          VersionModal: true,
        },
      },
    });
    const tree = wrapper.findComponent({ name: 'BasicLeftTree' });
    tree.vm.$emit('select', 'category-1');
    tableState.reload.mockClear();

    tree.vm.$emit('reset');

    expect(tableState.reload).toHaveBeenCalledWith({
      page: 1,
      searchInfo: { bizEnabled: 'enabled', keyword: '无菌' },
    });
  });

  it('重置顶部搜索表单时保留当前分类', async () => {
    formState.values = { bizStatus: 'PUBLISHED', keyword: '无菌' };
    formState.resetFields.mockImplementationOnce(async () => {
      formState.values = {};
    });
    const wrapper = mount(TemplatePage, {
      global: {
        stubs: {
          'a-button': true,
          'a-form-item': true,
          'a-tag': true,
          'a-textarea': true,
          VersionModal: true,
        },
      },
    });
    wrapper.findComponent({ name: 'BasicLeftTree' }).vm.$emit('select', 'category-1');
    tableState.reload.mockClear();

    wrapper.findComponent({ name: 'BasicForm' }).vm.$emit('reset');

    await vi.waitFor(() =>
      expect(tableState.reload).toHaveBeenCalledWith({
        page: 1,
        searchInfo: { mubanFenlei: 'category-1' },
      }),
    );
  });

  it('uses the low-code page skeleton and required columns without cards', () => {
    shallowMount(TemplatePage, { global: { stubs: { 'a-button': true, 'a-form-item': true, 'a-tag': true, 'a-textarea': true } } });
    const titles = tableState.config.columns.map((column: any) => column.title);
    const testDefinitionColumn = tableState.config.columns.find((column: any) => column.title === '检验项目');
    const templateCategoryColumn = tableState.config.columns.find((column: any) => column.title === '模板分类');

    expect(pageSource).toContain('<div class="jnpf-content-wrapper">');
    expect(pageSource).toContain('<BasicForm');
    expect(pageSource).toContain('<BasicVxeTable');
    expect(pageSource).toContain('<TableAction');
    expect(pageSource).not.toContain('<BasicModal');
    expect(pageSource).not.toContain('a-card');
    expect(titles).toEqual(['模板编号', '检验项目', '模板分类', '生效版本', '发布状态', '启用状态', '生效时间', '字段数', '更新时间', '创建时间']);
    expect(testDefinitionColumn.dataIndex).toBe('jianyanXiangmuMingcheng');
    expect(templateCategoryColumn.dataIndex).toBe('mubanFenleiMingcheng');
  });

  it('主列表按模板编号请求目录聚合结果', async () => {
    shallowMount(TemplatePage, { global: { stubs: { 'a-button': true, 'a-form-item': true, 'a-tag': true, 'a-textarea': true } } });
    const query = tableState.config.beforeFetch({ currentPage: 1, pageSize: 20 });

    await tableState.config.api(query);

    expect(apiMocks.getTemplateDirectory).toHaveBeenCalledWith({ currentPage: 1, pageSize: 20 });
  });

  it('显示生效版本，无当前版本时显示未生效', () => {
    const effective = mount(TemplatePage, {
      global: { stubs: { 'a-button': true, 'a-tag': true } },
    });
    expect(effective.text()).toContain('R01');

    tableState.row = {
      bizEnabled: undefined,
      bizStatus: undefined,
      mubanBianhao: 'TMP-001',
      shengxiaoMubanBanben: undefined,
      shengxiaoMubanId: undefined,
    };
    const inactive = mount(TemplatePage, {
      global: { stubs: { 'a-button': true, 'a-tag': true } },
    });
    expect(inactive.text()).toContain('未生效');
  });

  it('shows the test definition name and falls back to its id', () => {
    tableState.row = { ...tableState.row, jianyanXiangmu: 'item-1' };
    const fallback = mount(TemplatePage, {
      global: { stubs: { 'a-button': true, 'a-form-item': true, 'a-tag': true, 'a-textarea': true, HealthDrawer: true, VersionModal: true } },
    });
    expect(fallback.text()).toContain('item-1');

    tableState.row = { ...tableState.row, jianyanXiangmuMingcheng: '无菌检查' };
    const resolved = mount(TemplatePage, {
      global: { stubs: { 'a-button': true, 'a-form-item': true, 'a-tag': true, 'a-textarea': true, HealthDrawer: true, VersionModal: true } },
    });
    expect(resolved.text()).toContain('无菌检查');
  });

  it('shows the template category name and falls back to its id', () => {
    tableState.row = { ...tableState.row, mubanFenlei: 'category-1' };
    const fallback = mount(TemplatePage, {
      global: { stubs: { 'a-button': true, 'a-form-item': true, 'a-tag': true, 'a-textarea': true, HealthDrawer: true, VersionModal: true } },
    });
    expect(fallback.text()).toContain('category-1');

    tableState.row = { ...tableState.row, mubanFenleiMingcheng: '检验记录' };
    const resolved = mount(TemplatePage, {
      global: { stubs: { 'a-button': true, 'a-form-item': true, 'a-tag': true, 'a-textarea': true, HealthDrawer: true, VersionModal: true } },
    });
    expect(resolved.text()).toContain('检验记录');
  });

  it('主列表只保留模板目录级操作', () => {
    mount(TemplatePage, {
      global: { stubs: { 'a-button': true, 'a-form-item': true, 'a-tag': true, 'a-textarea': true, HealthDrawer: true, VersionModal: true } },
    });

    expect(tableState.actions.map((action) => action.label)).toEqual(['版本']);
  });

  it('从操作列打开指定模板的版本列表', async () => {
    mount(TemplatePage, {
      global: {
        stubs: { 'a-button': true, 'a-form-item': true, 'a-tag': true, 'a-textarea': true, HealthDrawer: true, VersionDrawer: true, VersionModal: true },
      },
    });

    const versions = tableState.actions.find((action) => action.label === '版本');
    expect(versions).toBeTruthy();
    await versions.onClick();

    expect(modalState.opened).toContainEqual({
      data: { mubanBianhao: 'TMP-001' },
      key: 'versionList',
    });
  });

  it('在列表内容区使用低代码平台默认容器打开新增表单', async () => {
    const wrapper = mount(TemplatePage, {
      global: { stubs: { 'a-button': ButtonStub, 'a-form-item': true, 'a-tag': true, 'a-textarea': true, HealthDrawer: true, VersionModal: true } },
    });
    const localForm = wrapper.findComponent({ name: 'GlobalFormModal' });

    expect(localForm.exists()).toBe(true);
    expect(localForm.props('listenGlobal')).toBe(false);
    expect(localForm.element.closest('.jnpf-content-wrapper')).not.toBeNull();

    const addButton = wrapper.findAll('button').find((button) => button.text() === '新增模板');
    expect(addButton).toBeTruthy();
    await addButton!.trigger('click');

    expect(localFormOpenMock).toHaveBeenCalledWith({
      modelId: '854727805680747141',
      onConfirm: expect.any(Function),
      title: '新增电子记录模板',
    });
    expect(pageSource).not.toMatch(/type: '(?:modal|drawer|fullScreen)'/);
  });
});
