import { mount } from '@vue/test-utils';
import Antd from 'ant-design-vue';
import { describe, expect, it } from 'vitest';

import DocumentFieldList from '../../src/components/DocumentFieldList.vue';
import type { OfficeContentControl } from '../../src/onlyoffice/types';

const controls: OfficeContentControl[] = [
  { Alias: '样品编号', ControlType: 'text', InternalId: 'single-1', Tag: 'eln.field.sample_id' },
  { Alias: '检测结果', ControlType: 'dropdown', InternalId: 'repeat-1', Tag: 'eln.repeat.results.row_01.value' },
  { Alias: '', InternalId: 'other-1', Tag: 'custom.control' },
  { InternalId: '', Tag: '' },
];

function mountList(props: { controls?: OfficeContentControl[]; disabled?: boolean; status?: 'initializing' | 'ready' | 'working' | 'error' } = {}) {
  return mount(DocumentFieldList, {
    props: { controls: props.controls ?? [], status: props.status ?? 'ready', disabled: props.disabled },
    global: { plugins: [Antd] },
  });
}

describe('DocumentFieldList', () => {
  it('为空列表提供摘要和明确空状态', () => {
    const wrapper = mountList();

    expect(wrapper.get('[data-test="control-summary"]').text()).toBe('控件 0，普通 0，表格 0');
    expect(wrapper.get('[data-test="empty-controls"]').text()).toBe('当前文档没有内容控件');
  });

  it.each(['initializing', 'working', 'error'] as const)('%s 且列表为空时不下空文档结论', (status) => {
    const wrapper = mountList({ status });

    expect(wrapper.find('[data-test="empty-controls"]').exists()).toBe(false);
    expect(wrapper.find('[data-test="empty-search-result"]').exists()).toBe(false);
  });

  it('按 Tag 分类并显示字段位置、具体类型与精确摘要', () => {
    const wrapper = mountList({ controls });

    expect(wrapper.get('[data-test="control-summary"]').text()).toBe('控件 4，普通 1，表格 1');
    const metadata = wrapper.findAll('[data-test="control-metadata"]').map((item) => item.text());
    expect(metadata).toEqual(['sample_id · 单行文本', '重复表格 · results · row_01 · value · 下拉选择', '非 ELN 内容控件', '非 ELN 内容控件']);
    expect(wrapper.get('[data-test="control-list"]').attributes('role')).toBe('list');
  });

  it('显示五种具体类型并为缺失类型的 ELN 控件提供兜底', () => {
    const typedControls: OfficeContentControl[] = [
      { Alias: '文本', ControlType: 'text', InternalId: '1', Tag: 'eln.field.text' },
      { Alias: '下拉', ControlType: 'dropdown', InternalId: '2', Tag: 'eln.field.dropdown' },
      { Alias: '复选', ControlType: 'checkbox', InternalId: '3', Tag: 'eln.field.checkbox' },
      { Alias: '日期', ControlType: 'date', InternalId: '4', Tag: 'eln.field.date' },
      { Alias: '多行', ControlType: 'multiline', InternalId: '5', Tag: 'eln.field.multiline' },
      { Alias: '旧字段', InternalId: '6', Tag: 'eln.field.legacy' },
    ];

    const wrapper = mountList({ controls: typedControls });

    expect(wrapper.findAll('[data-test="control-metadata"]').map((item) => item.text())).toEqual([
      'text · 单行文本',
      'dropdown · 下拉选择',
      'checkbox · 复选框',
      'date · 日期',
      'multiline · 多行文本',
      'legacy · 未知类型',
    ]);
  });

  it('显示 Alias/Tag fallback，缺少 InternalId 的项目不可定位', () => {
    const wrapper = mountList({ controls });
    const items = wrapper.findAll('[data-test="control-item"]');

    expect(items[0]!.text()).toContain('样品编号');
    expect(items[0]!.text()).toContain('eln.field.sample_id');
    expect(items[2]!.text()).toContain('未命名字段 3');
    expect(items[3]!.text()).toContain('未命名字段 4');
    expect(items[3]!.text()).toContain('无 Tag');
    expect(items[3]!.attributes('disabled')).toBeDefined();
  });

  it.each([
    ['名称', '样品编号', ['样品编号']],
    ['完整 Tag', 'ELN.FIELD.SAMPLE_ID', ['样品编号']],
    ['重复组编码', 'RESULTS', ['检测结果']],
    ['重复行 ID', 'ROW_01', ['检测结果']],
    ['重复字段编码', 'VALUE', ['检测结果']],
    ['具体类型', '下拉选择', ['检测结果']],
  ])('按%s进行不区分大小写的包含搜索', async (_label, keyword, expectedAliases) => {
    const wrapper = mountList({ controls });

    await wrapper.get('[data-test="field-search"]').setValue(keyword);

    expect(wrapper.findAll('[data-test="control-item"]').map((item) => item.text())).toEqual(
      expectedAliases.map((alias) => expect.stringContaining(alias)),
    );
    expect(wrapper.get('[data-test="control-summary"]').text()).toBe('控件 4，普通 1，表格 1');
  });

  it('有内容控件但搜索无匹配时显示明确空状态', async () => {
    const wrapper = mountList({ controls });

    await wrapper.get('[data-test="field-search"]').setValue('不存在的字段');

    expect(wrapper.find('[data-test="control-list"]').exists()).toBe(false);
    expect(wrapper.get('[data-test="empty-search-result"]').text()).toBe('没有匹配的文档字段');
  });

  it('点击项目只发出 select，disabled 时所有项目不可定位', async () => {
    const wrapper = mountList({ controls });

    await wrapper.findAll('[data-test="control-item"]')[1]!.trigger('click');
    expect(wrapper.emitted('select')).toEqual([['repeat-1']]);

    await wrapper.setProps({ disabled: true });
    expect(wrapper.findAll('[data-test="control-item"]').every((item) => item.attributes('disabled') !== undefined)).toBe(true);
  });

  it('只为 ELN 字段提供解除确认，确认后只发出 delete', async () => {
    const wrapper = mountList({ controls });
    const deletes = wrapper.findAll('[data-test="delete-control"]');

    expect(deletes).toHaveLength(2);
    expect(deletes[0]!.attributes()).toMatchObject({ 'aria-label': '解除标注：样品编号', title: '解除标注' });
    const confirms = wrapper.findAllComponents({ name: 'APopconfirm' });
    expect(confirms[0]!.props()).toMatchObject({ title: '解除该字段标注并保留内容？', okText: '解除', cancelText: '取消' });

    confirms[0]!.vm.$emit('confirm');
    await wrapper.vm.$nextTick();
    expect(wrapper.emitted('delete')).toEqual([['single-1']]);
    expect(wrapper.emitted('select')).toBeUndefined();
  });

  it('disabled 和 working 时禁用删除入口', async () => {
    const wrapper = mountList({ controls, disabled: true });
    expect(wrapper.findAll('[data-test="delete-control"]').every((button) => button.attributes('disabled') !== undefined)).toBe(true);

    await wrapper.setProps({ disabled: false, status: 'working' });
    expect(wrapper.findAll('[data-test="delete-control"]').every((button) => button.attributes('disabled') !== undefined)).toBe(true);
  });

  it('刷新按钮有稳定标识，working 和 disabled 时禁用且只发出 refresh', async () => {
    const wrapper = mountList({ controls });
    const refresh = wrapper.get('[data-test="refresh-controls"]');

    expect(refresh.attributes()).toMatchObject({ 'aria-label': '刷新内容控件', title: '刷新内容控件' });
    await refresh.trigger('click');
    expect(wrapper.emitted('refresh')).toHaveLength(1);

    await wrapper.setProps({ status: 'working' });
    expect(wrapper.get('[data-test="refresh-controls"]').attributes('disabled')).toBeDefined();
    await wrapper.setProps({ status: 'ready', disabled: true });
    expect(wrapper.get('[data-test="refresh-controls"]').attributes('disabled')).toBeDefined();
  });
});
