import type { TemplateBinding, TemplateFieldOption } from '../../src/domain/types';
import type { OfficeContentControl } from '../../src/onlyoffice/types';

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

import Antd, { Modal } from 'ant-design-vue';
import { describe, expect, it, vi } from 'vitest';

import DocumentFieldList from '../../src/components/DocumentFieldList.vue';

const controls: OfficeContentControl[] = [
  { Alias: '结果', ControlType: 'text', InternalId: 'primary-control', Tag: 'eln.field.result', Text: '12.3' },
  { Alias: '结果', ControlType: 'text', InternalId: 'reference-control', Tag: 'eln.ref.result.abc', Text: '12.3' },
  { Alias: '旧重复', ControlType: 'text', InternalId: 'repeat-control', Tag: 'eln.repeat.group.row.value' },
];
const bindings: TemplateBinding[] = [
  {
    controlAlias: '结果',
    controlConfig: {},
    controlRole: 'PRIMARY',
    controlTag: 'eln.field.result',
    controlType: 'TEXT',
    fieldCode: 'result',
    fieldId: 'field',
    fieldVersionId: 'version',
    id: 'primary',
    primaryBindingId: null,
    status: 'ACTIVE',
    templateId: 'template',
    version: 2,
  },
  {
    controlAlias: '结果',
    controlConfig: {},
    controlRole: 'REFERENCE',
    controlTag: 'eln.ref.result.abc',
    controlType: 'TEXT',
    fieldCode: 'result',
    fieldId: 'field',
    fieldVersionId: 'version',
    id: 'reference',
    primaryBindingId: 'primary',
    status: 'ACTIVE',
    templateId: 'template',
    version: 1,
  },
];
const groupedControls: OfficeContentControl[] = [
  { Alias: '合格', ControlType: 'checkbox', InternalId: 'passed-control', Tag: 'eln.field.passed' },
  { Alias: '不合格', ControlType: 'checkbox', InternalId: 'failed-control', Tag: 'eln.field.failed' },
  { Alias: '需复核', ControlType: 'checkbox', InternalId: 'review-control', Tag: 'eln.field.review' },
];
const groupedBindings: TemplateBinding[] = [
  {
    checkboxGroupCode: 'inspection_result',
    controlAlias: '合格',
    controlConfig: { defaultChecked: false },
    controlRole: 'PRIMARY',
    controlTag: 'eln.field.passed',
    controlType: 'CHECKBOX',
    fieldCode: 'passed',
    fieldId: 'passed-field',
    fieldVersionId: 'passed-version',
    id: 'passed',
    primaryBindingId: null,
    status: 'ACTIVE',
    stepId: 'step-1',
    templateId: 'template',
    version: 2,
  },
  {
    checkboxGroupCode: 'inspection_result',
    controlAlias: '不合格',
    controlConfig: { defaultChecked: false },
    controlRole: 'PRIMARY',
    controlTag: 'eln.field.failed',
    controlType: 'CHECKBOX',
    fieldCode: 'failed',
    fieldId: 'failed-field',
    fieldVersionId: 'failed-version',
    id: 'failed',
    primaryBindingId: null,
    status: 'ACTIVE',
    stepId: 'step-1',
    templateId: 'template',
    version: 3,
  },
  {
    checkboxGroupCode: 'review_result',
    controlAlias: '需复核',
    controlConfig: { defaultChecked: false },
    controlRole: 'PRIMARY',
    controlTag: 'eln.field.review',
    controlType: 'CHECKBOX',
    fieldCode: 'review',
    fieldId: 'review-field',
    fieldVersionId: 'review-version',
    id: 'review',
    primaryBindingId: null,
    status: 'ACTIVE',
    stepId: 'step-1',
    templateId: 'template',
    version: 1,
  },
];
const fields: TemplateFieldOption[] = [
  {
    alias: '结果',
    controlConfig: {},
    fieldCode: 'result',
    fieldId: 'field',
    fieldVersionId: 'version',
    isCurrent: false,
    label: '结果 v1',
    required: false,
    scope: 'GLOBAL',
    source: 'NONE',
    type: 'TEXT',
    versionStatus: 'PUBLISHED',
  },
  {
    alias: '结果',
    controlConfig: {},
    fieldCode: 'result',
    fieldId: 'field',
    fieldVersionId: 'published-v2',
    isCurrent: true,
    label: '结果 v2',
    required: false,
    scope: 'GLOBAL',
    source: 'NONE',
    type: 'TEXT',
    versionStatus: 'PUBLISHED',
  },
  {
    alias: '结果',
    controlConfig: {},
    fieldCode: 'result',
    fieldId: 'field',
    fieldVersionId: 'pre-release-v3',
    isCurrent: false,
    label: '结果 v3',
    required: false,
    scope: 'GLOBAL',
    source: 'NONE',
    type: 'TEXT',
    versionStatus: 'PRE_RELEASE',
  },
  {
    alias: '结果',
    controlConfig: {},
    fieldCode: 'result',
    fieldId: 'field',
    fieldVersionId: 'draft-v4',
    isCurrent: false,
    label: '结果 v4',
    required: false,
    scope: 'GLOBAL',
    source: 'NONE',
    type: 'TEXT',
    versionStatus: 'DRAFT',
  },
  {
    alias: '其他',
    controlConfig: {},
    fieldCode: 'other',
    fieldId: 'other-field',
    fieldVersionId: 'other-version',
    isCurrent: true,
    label: '其他',
    required: false,
    scope: 'GLOBAL',
    source: 'NONE',
    type: 'TEXT',
    versionStatus: 'PUBLISHED',
  },
];
const DropdownStub = defineComponent({
  name: 'ADropdown',
  setup(_, { slots }) {
    return () => h('div', [slots.default?.(), slots.overlay?.()]);
  },
});
const TooltipStub = defineComponent({
  name: 'ATooltip',
  props: {
    open: { default: undefined, type: Boolean },
    placement: { default: undefined, type: String },
    title: { default: undefined, type: String },
  },
  setup(_, { slots }) {
    return () => h('span', slots.default?.());
  },
});
function mountList(extra: Record<string, unknown> = {}) {
  return mount(DocumentFieldList, {
    props: { bindings, controls, fields, status: 'ready', ...extra },
    global: {
      plugins: [Antd],
      stubs: {
        'a-dropdown': DropdownStub,
        'a-tooltip': TooltipStub,
      },
    },
  });
}

describe('documentFieldList', () => {
  it('输入停止 300ms 后自动搜索且不显示搜索按钮', async () => {
    vi.useFakeTimers();
    const wrapper = mountList();

    try {
      const input = wrapper.getComponent({ name: 'AInput' });
      expect(wrapper.findComponent({ name: 'AInputSearch' }).exists()).toBe(false);

      input.vm.$emit('update:value', '旧重复');
      await nextTick();
      expect(wrapper.findAll('[data-test="control-item"]')).toHaveLength(3);

      vi.advanceTimersByTime(299);
      await nextTick();
      expect(wrapper.findAll('[data-test="control-item"]')).toHaveLength(3);

      vi.advanceTimersByTime(1);
      await nextTick();
      expect(wrapper.findAll('[data-test="control-item"]')).toHaveLength(1);
      expect(wrapper.get('[data-test="control-item"]').text()).toContain('旧重复');

      input.vm.$emit('update:value', '不存在的字段');
      await nextTick();
      vi.advanceTimersByTime(300);
      await nextTick();
      expect(wrapper.getComponent({ name: 'AEmpty' }).props('description')).toBe('没有匹配的文档字段');
    } finally {
      wrapper.unmount();
      vi.useRealTimers();
    }
  });

  it('提供全部、选择组和异常分段，并为异常显示数量', async () => {
    const wrapper = mountList({ controls: controls.slice(1) });
    const segmented = wrapper.getComponent({ name: 'ASegmented' });

    expect(segmented.props('options').map((option: { value: string }) => option.value)).toEqual(['all', 'group', 'anomaly']);
    expect(wrapper.findAll('.document-filter-badge')).toHaveLength(1);
    expect(wrapper.get('.document-filter .ant-badge-count').text()).toBe('2');
    expect(wrapper.get('.document-filter .ant-badge-count').attributes('style')).toContain('background-color: #ff4d4f');
    expect(wrapper.get('.document-filter').text()).toContain('全部');
    expect(wrapper.find('[data-test="control-summary"]').exists()).toBe(false);
    segmented.vm.$emit('update:value', 'anomaly');
    await nextTick();
    expect(wrapper.findAll('[data-test="control-item"]')).toHaveLength(1);
    expect(wrapper.get('[data-test="control-item"]').text()).toContain('旧重复');
    expect(wrapper.findAll('[data-test="missing-binding"]')).toHaveLength(1);
  });

  it('全部、选择组和异常分段复用同一位置的 Empty 组件', async () => {
    const wrapper = mountList({ bindings: [], controls: [] });
    const segmented = wrapper.getComponent({ name: 'ASegmented' });
    const assertEmpty = (description: string) => {
      const empty = wrapper.get('[data-test="document-empty"]');
      expect(empty.classes()).toContain('empty-controls');
      expect(wrapper.findAllComponents({ name: 'AEmpty' })).toHaveLength(1);
      expect(wrapper.getComponent({ name: 'AEmpty' }).props('description')).toBe(description);
    };

    assertEmpty('当前文档没有内容控件');
    segmented.vm.$emit('update:value', 'group');
    await nextTick();
    assertEmpty('没有匹配的选择组');
    segmented.vm.$emit('update:value', 'anomaly');
    await nextTick();
    assertEmpty('没有异常字段');
  });

  it('行内标签关联同组字段，搜索同时匹配组编码', async () => {
    vi.useFakeTimers();
    const wrapper = mountList({ bindings: groupedBindings, controls: groupedControls });

    try {
      const labels = wrapper.findAll('[data-test="checkbox-group-label"]');
      expect(labels).toHaveLength(3);
      expect(labels[0]!.text()).toContain('选择组 · inspection_result');
      expect(labels[0]!.attributes('style')).toContain('color:');
      expect(labels[0]!.attributes('style')).not.toContain('border');

      wrapper.getComponent({ name: 'AInput' }).vm.$emit('update:value', 'inspection_result');
      vi.advanceTimersByTime(300);
      await nextTick();
      expect(wrapper.findAll('[data-test="control-item"]')).toHaveLength(2);
    } finally {
      wrapper.unmount();
      vi.useRealTimers();
    }
  });

  it('选择组视图显示成员、作用域和单成员异常，并可定位字段', async () => {
    const wrapper = mountList({
      bindings: groupedBindings,
      controls: groupedControls,
      steps: [{ id: 'step-1', name: '样品制备', order: 1 }],
    });
    const segmented = wrapper.getComponent({ name: 'ASegmented' });

    segmented.vm.$emit('update:value', 'group');
    await nextTick();

    const groups = wrapper.findAll('[data-test="checkbox-group"]');
    expect(groups).toHaveLength(2);
    expect(groups[0]!.text()).toContain('inspection_result');
    expect(groups[0]!.text()).toContain('2 个成员');
    expect(groups[0]!.text()).toContain('步骤：样品制备');
    expect(groups[0]!.text()).not.toContain('步骤：step-1');
    expect(wrapper.get('[data-test="checkbox-group-anomaly"]').text()).toContain('只有一个成员');
    await groups[0]!.find('[data-test="checkbox-group-member-locate"]').trigger('click');
    expect(wrapper.emitted('select')).toEqual([['passed-control']]);
  });

  it('重复复选框按重复组展示并可修改选择组', async () => {
    const repeatBindings: TemplateBinding[] = ['qualified', 'unqualified'].map((fieldCode, index) => ({
      checkboxGroupCode: 'row_result',
      controlAlias: index === 0 ? '合格' : '不合格',
      controlConfig: { defaultChecked: false },
      controlRole: 'REPEAT',
      controlTag: `eln.repeat.results.prototype.${fieldCode}`,
      controlType: 'CHECKBOX',
      fieldCode,
      fieldId: `${fieldCode}-field`,
      fieldVersionId: `${fieldCode}-version`,
      id: fieldCode,
      primaryBindingId: null,
      repeatGroupCode: 'results',
      status: 'ACTIVE',
      templateId: 'template',
      version: index + 1,
    }));
    const repeatControls: OfficeContentControl[] = repeatBindings.map((binding) => ({
      Alias: binding.controlAlias || '',
      ControlType: 'checkbox',
      InternalId: `${binding.id}-control`,
      Tag: binding.controlTag,
    }));
    const wrapper = mountList({ bindings: repeatBindings, controls: repeatControls });
    const segmented = wrapper.getComponent({ name: 'ASegmented' });

    segmented.vm.$emit('update:value', 'group');
    await nextTick();
    expect(wrapper.get('[data-test="checkbox-group"]').text()).toContain('重复组：results');
    expect(wrapper.get('[data-test="checkbox-group"]').text()).toContain('2 个成员');

    segmented.vm.$emit('update:value', 'all');
    await nextTick();
    await wrapper.findAll('[data-test="change-checkbox-group"]')[0]!.trigger('click');
    wrapper.getComponent({ name: 'AAutoComplete' }).vm.$emit('update:value', 'row_decision');
    await nextTick();
    await wrapper.get('[data-test="save-checkbox-group"]').trigger('click');
    expect(wrapper.emitted('change-checkbox-group')).toEqual([
      ['qualified', { groupCode: 'row_decision', maxSelected: 1, minSelected: 0 }, 1],
    ]);
  });

  it('同一选择组跨作用域时在组视图和异常视图显示冲突上下文', async () => {
    const conflictingBindings = groupedBindings.map((binding) => (binding.id === 'failed' ? { ...binding, stepId: 'step-2' } : binding));
    const wrapper = mountList({ bindings: conflictingBindings, controls: groupedControls });
    const segmented = wrapper.getComponent({ name: 'ASegmented' });

    segmented.vm.$emit('update:value', 'group');
    await nextTick();
    const conflicted = wrapper.findAll('[data-test="checkbox-group"]').find((group) => group.text().includes('inspection_result'))!;
    expect(conflicted.get('[data-test="checkbox-group-anomaly"]').text()).toContain('跨越多个作用域');
    expect(conflicted.text()).toContain('步骤：step-1');
    expect(conflicted.text()).toContain('步骤：step-2');

    segmented.vm.$emit('update:value', 'anomaly');
    await nextTick();
    expect(wrapper.get('[data-test="checkbox-group"]').text()).toContain('inspection_result');
  });

  it('默认值越界和非法成员都进入选择组异常视图', async () => {
    const anomalyBindings: TemplateBinding[] = [
      { ...groupedBindings[0]!, controlConfig: { defaultChecked: true } },
      { ...groupedBindings[1]!, controlConfig: { defaultChecked: true } },
      {
        ...groupedBindings[2]!,
        checkboxGroupCode: 'invalid_members',
        controlRole: 'REFERENCE',
      },
      {
        ...groupedBindings[2]!,
        checkboxGroupCode: 'invalid_members',
        controlAlias: '文本字段',
        controlType: 'TEXT',
        id: 'invalid-text',
      },
    ];
    const wrapper = mountList({
      bindings: anomalyBindings,
      checkboxGroups: [{ groupCode: 'inspection_result', maxSelected: 1, minSelected: 0, version: 1 }],
      controls: groupedControls,
    });
    const segmented = wrapper.getComponent({ name: 'ASegmented' });

    segmented.vm.$emit('update:value', 'anomaly');
    await nextTick();

    const groups = wrapper.findAll('[data-test="checkbox-group"]');
    expect(groups).toHaveLength(2);
    expect(groups.find((group) => group.text().includes('inspection_result'))!.text()).toContain('默认勾选数不符合数量规则');
    expect(groups.find((group) => group.text().includes('invalid_members'))!.text()).toContain('包含不允许入组的字段');
  });

  it('可设置、修改或移出选择组，并携带完整规则和绑定当前版本', async () => {
    const wrapper = mountList({
      bindings: groupedBindings,
      checkboxGroups: [
        { groupCode: 'inspection_result', maxSelected: 1, minSelected: 0, version: 1 },
        { groupCode: 'review_result', maxSelected: 3, minSelected: 1, version: 2 },
      ],
      controls: groupedControls,
    });

    await wrapper.findAll('[data-test="change-checkbox-group"]')[0]!.trigger('click');
    expect(wrapper.find('[data-test="document-main"]').exists()).toBe(false);
    const input = wrapper.getComponent({ name: 'AAutoComplete' });
    input.vm.$emit('update:value', 'review_result');
    await nextTick();
    await wrapper.get('[data-test="save-checkbox-group"]').trigger('click');
    expect((wrapper.get('[data-test="checkbox-group-edit-min"]').element as HTMLInputElement).value).toBe('1');
    expect(wrapper.get('[data-test="checkbox-group-edit-min"]').attributes('disabled')).toBeDefined();
    expect(wrapper.emitted('change-checkbox-group')).toEqual([
      ['passed', { groupCode: 'review_result', maxSelected: 3, minSelected: 1 }, 2],
    ]);

    const removeWrapper = mountList({ bindings: groupedBindings, controls: groupedControls });
    await removeWrapper.findAll('[data-test="remove-checkbox-group"]')[0]!.trigger('click');
    expect(removeWrapper.emitted('change-checkbox-group')).toEqual([['passed', null, 2]]);
  });

  it('选择组视图展示权威规则并可修改共享上下限', async () => {
    const wrapper = mountList({
      bindings: groupedBindings,
      checkboxGroups: [{ groupCode: 'inspection_result', maxSelected: 2, minSelected: 1, version: 4 }],
      controls: groupedControls,
    });
    const segmented = wrapper.getComponent({ name: 'ASegmented' });
    segmented.vm.$emit('update:value', 'group');
    await nextTick();

    const group = wrapper.findAll('[data-test="checkbox-group"]').find((item) => item.text().includes('inspection_result'))!;
    expect(group.text()).toContain('至少 1 项，最多 2 项');
    await group.get('[data-test="edit-checkbox-group-rule"]').trigger('click');
    await wrapper.get('[data-test="checkbox-group-rule-min"]').setValue(0);
    await wrapper.get('[data-test="checkbox-group-rule-max"]').setValue(3);
    await wrapper.get('[data-test="save-checkbox-group-rule"]').trigger('click');

    expect(wrapper.emitted('change-checkbox-group-rule')).toEqual([['inspection_result', 0, 3, 4]]);
  });

  it('区分主字段、字段引用和重复控件，并显示缺失绑定异常', () => {
    const wrapper = mountList({ controls: controls.slice(1) });
    const referenceRow = wrapper.findAll('[data-test="control-item"]').find((item) => item.text().includes('引用'))!;
    const roles = wrapper.findAll('[data-test="control-role"]');

    expect(referenceRow.get('.control-metadata').text()).toBe('result');
    expect(referenceRow.text()).not.toContain('字段编码：');
    expect(wrapper.findAll('.control-metadata').some((item) => item.text() === 'value')).toBe(true);
    expect(wrapper.findComponent({ name: 'ATag' }).exists()).toBe(false);
    expect(roles.map((item) => item.attributes('data-role'))).toEqual(['repeat', 'reference']);
    expect(roles[0]!.text()).toBe('·重复行');
    expect(wrapper.findAll('[data-test="control-type"]').map((item) => item.text())).toEqual(['单行文本', '单行文本']);
    expect(wrapper.get('[data-test="missing-binding"]').text()).toContain('主字段控件缺失');
  });

  it('已绑定数值字段按字段语义类型显示，不降级为 Word 单行文本控件类型', () => {
    const wrapper = mountList({
      bindings: bindings.slice(0, 1),
      controls: controls.slice(0, 1),
      fields: [{ ...fields[0]!, type: 'DECIMAL' }],
    });

    expect(wrapper.get('[data-test="control-type"]').text()).toBe('数值');
  });

  it('绑定上下文缺失时仍按控件类型显示主字段角色', () => {
    const wrapper = mountList({ bindings: [], controls: controls.slice(0, 1) });
    const role = wrapper.get('[data-test="control-role"]');

    expect(role.attributes('data-role')).toBe('primary');
    expect(role.text()).toBe('·主字段');
    expect(wrapper.get('[data-test="anomaly-reason"]').text()).toBe('文档控件没有有效或待确认绑定');
  });

  it('缺失绑定异常显示 DOCX 控件已缺失的原因', () => {
    const wrapper = mountList({ controls: controls.slice(1) });

    expect(wrapper.get('[data-test="missing-binding"] [data-test="anomaly-reason"]').text()).toBe('绑定存在但 DOCX 控件已缺失');
  });

  it('孤立控件提供删除操作并携带控件内部 ID', async () => {
    const wrapper = mountList({ bindings: [], controls: controls.slice(0, 1) });
    const confirmSpy = vi.spyOn(Modal, 'confirm').mockReturnValue({ destroy: vi.fn(), update: vi.fn() } as ReturnType<typeof Modal.confirm>);

    try {
      const removeButton = wrapper.findAllComponents({ name: 'AButton' }).find((button) => button.attributes('data-test') === 'remove-orphan-control')!;

      expect(removeButton.props('shape')).toBe('circle');
      expect(removeButton.attributes('aria-label')).toBe('删除异常控件');
      await removeButton.trigger('click');
      await (confirmSpy.mock.calls[0]![0].onOk as () => void)();

      expect(wrapper.emitted('remove-orphan-control')).toEqual([['primary-control']]);
    } finally {
      confirmSpy.mockRestore();
    }
  });

  it('全部视图将异常控件排在普通控件之前', () => {
    const wrapper = mountList();
    const rows = wrapper.findAll('[data-test="control-item"]');

    expect(rows[0]!.text()).toContain('旧重复');
    expect(rows[1]!.text()).toContain('结果');
  });

  it('重复主字段不直接插入，向上发出引用创建动作', async () => {
    const wrapper = mountList();
    await wrapper.get('[data-test="insert-reference-primary"]').trigger('click');
    expect(wrapper.emitted('insert-reference')).toEqual([['primary']]);
  });

  it('主字段删除和引用提升使用绑定 ID，普通非 ELN 控件没有业务动作', async () => {
    const wrapper = mountList({ controls: [...controls, { InternalId: 'other', Tag: 'custom.tag' }] });
    const confirmSpy = vi.spyOn(Modal, 'confirm').mockReturnValue({ destroy: vi.fn(), update: vi.fn() } as ReturnType<typeof Modal.confirm>);

    try {
      expect(wrapper.get('[data-test="remove-binding"]').element.closest('.ant-menu-item')).not.toBeNull();
      expect(wrapper.find('.row-action-overlay').exists()).toBe(false);
      await wrapper.get('[data-test="remove-binding"]').trigger('click');
      expect(confirmSpy).toHaveBeenCalledWith(expect.objectContaining({ okText: '删除', okType: 'danger', title: '删除该字段控件？' }));
      await (confirmSpy.mock.calls[0]![0].onOk as () => void)();
      await wrapper.get('[data-test="promote-reference"]').trigger('click');
      expect(wrapper.emitted('remove-binding')).toEqual([['primary', 'primary-control']]);
      expect(wrapper.emitted('promote-reference')).toEqual([['reference']]);
      expect(wrapper.findAll('[data-test="remove-binding"]')).toHaveLength(2);
    } finally {
      confirmSpy.mockRestore();
    }
  });

  it('repair 仅针对缺失绑定并复用原 binding ID', async () => {
    const wrapper = mountList({ controls: controls.slice(1) });
    await wrapper.get('[data-test="repair-binding"]').trigger('click');
    expect(wrapper.emitted('repair')).toEqual([['primary']]);
  });

  it('刷新和定位仍可用，working 时禁用写动作', async () => {
    const wrapper = mountList();
    const refreshButton = wrapper.findAllComponents({ name: 'AButton' }).find((button) => button.attributes('data-test') === 'refresh-controls')!;
    const refreshTooltip = wrapper.findAllComponents(TooltipStub).find((tooltip) => tooltip.props('title') === '刷新文档字段')!;
    const actionTooltip = wrapper.findAllComponents(TooltipStub).find((tooltip) => tooltip.props('title') === '更多操作')!;
    const actionDropdown = wrapper.findAllComponents(DropdownStub)[0]!;

    expect(refreshTooltip.props('placement')).toBe('topRight');
    expect(actionTooltip.props('open')).toBeUndefined();
    actionDropdown.vm.$emit('openChange', true);
    await nextTick();
    expect(actionTooltip.props('open')).toBe(false);
    expect(refreshButton.props('loading')).toBe(false);
    await wrapper.get('[data-test="refresh-controls"]').trigger('click');
    await wrapper
      .findAll('[data-test="control-item"]')
      .find((item) => item.text().includes('主字段'))!
      .trigger('click');
    expect(wrapper.emitted('refresh')).toHaveLength(1);
    expect(wrapper.emitted('select')).toEqual([['primary-control']]);
    await wrapper.setProps({ status: 'working' });
    expect(refreshButton.props('loading')).toBe(false);
    expect(refreshButton.props('disabled')).toBe(true);
    expect(wrapper.findAll('[data-write-action="true"]').every((item) => item.attributes('disabled') !== undefined)).toBe(true);
  });

  it('aCTIVE 主字段只允许升级到同字段的发布或预发布版本，并标记预发布风险', async () => {
    const wrapper = mountList();
    expect(wrapper.find('[data-test="upgrade-version"]').exists()).toBe(false);
    await wrapper.get('[data-test="open-upgrade-binding"]').trigger('click');
    expect(wrapper.find('[data-test="document-main"]').exists()).toBe(false);
    const upgradeSelect = wrapper.getComponent({ name: 'ASelect' });
    const optionValues = upgradeSelect.props('options').map((item: { value: string }) => item.value);
    expect(optionValues).toEqual(['published-v2', 'pre-release-v3']);
    expect(upgradeSelect.props('options')[1].label).toContain('预发布');
    expect(optionValues).not.toContain('draft-v4');
    expect(optionValues).not.toContain('other-version');

    (upgradeSelect.props()['onUpdate:value'] as (value: string) => void)('pre-release-v3');
    await nextTick();
    await wrapper.get('[data-test="upgrade-binding"]').trigger('click');
    expect(wrapper.emitted('upgrade-binding')).toEqual([['primary', 'pre-release-v3']]);
    expect(wrapper.text()).toContain('预发布版本仅供模板验证');
  });

  it('只读时保留刷新和定位，但包括 repair 在内的全部写动作均不 emit', async () => {
    const wrapper = mountList({ controls: controls.slice(1), readOnly: true });
    await wrapper
      .findAll('[data-test="control-item"]')
      .find((item) => item.text().includes('引用'))!
      .trigger('click');
    await wrapper.get('[data-test="repair-binding"]').trigger('click');
    expect(wrapper.emitted('select')).toEqual([['reference-control']]);
    expect(wrapper.get('[data-test="refresh-controls"]').attributes('disabled')).toBeUndefined();
    expect(wrapper.findAll('[data-write-action="true"]').every((item) => item.attributes('disabled') !== undefined)).toBe(true);
    expect(wrapper.emitted('repair')).toBeUndefined();
  });

  it('修复模式只保留目标恢复、刷新和定位动作', () => {
    const wrapper = mountList({ controls: controls.slice(1), repairBindingId: 'primary' });
    expect(wrapper.find('[data-test="insert-reference-primary"]').exists()).toBe(false);
    expect(wrapper.find('[data-test="promote-reference"]').exists()).toBe(false);
    expect(wrapper.find('[data-test="remove-binding"]').exists()).toBe(false);
    expect(wrapper.find('[data-test="upgrade-binding"]').exists()).toBe(false);
    expect(wrapper.get('[data-test="repair-binding"]').text()).toContain('在文档选择位置后恢复');
    expect(wrapper.get('[data-test="refresh-controls"]').attributes('disabled')).toBeUndefined();
  });
});
