import type { FormulaBindingCandidate } from '../../src/domain/formula-mapping';

import { DOMWrapper, mount } from '@vue/test-utils';

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

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

const candidates: Array<FormulaBindingCandidate & { label: string }> = [
  {
    id: 'amount',
    label: '样品量',
    controlRole: 'PRIMARY',
    status: 'ACTIVE',
    fieldDataType: 'DECIMAL',
    readSource: 'NONE',
    writeTarget: 'ELN_RECORD',
    batchMode: 'RECORD_PRIVATE',
  },
  {
    id: 'result',
    label: '浓度',
    controlRole: 'PRIMARY',
    status: 'ACTIVE',
    fieldDataType: 'DECIMAL',
    readSource: 'NONE',
    writeTarget: 'ELN_RECORD',
    batchMode: 'RECORD_PRIVATE',
  },
  {
    id: 'reference',
    label: '引用',
    controlRole: 'REFERENCE',
    status: 'ACTIVE',
    fieldDataType: 'DECIMAL',
    readSource: 'NONE',
    writeTarget: 'ELN_RECORD',
    batchMode: 'RECORD_PRIVATE',
  },
];

function mountPanel() {
  return mount(FormulaBindingPanel, {
    props: {
      candidates,
      versions: [
        {
          id: 'current',
          formulaCode: 'density',
          formulaName: '浓度',
          formulaEnabled: true,
          isCurrent: true,
          status: 'PUBLISHED',
          resultType: 'DECIMAL',
          slots: [{ code: 'amount', name: '样品量', required: true, type: 'DECIMAL' }],
        },
        {
          id: 'pre',
          formulaCode: 'density',
          formulaName: '浓度预发布',
          formulaEnabled: true,
          isCurrent: false,
          status: 'PRE_RELEASE',
          resultType: 'DECIMAL',
          slots: [],
        },
        {
          id: 'historic',
          formulaCode: 'density',
          formulaName: '浓度旧版',
          formulaEnabled: true,
          isCurrent: false,
          status: 'PUBLISHED',
          resultType: 'DECIMAL',
          slots: [],
        },
      ],
    },
    global: { plugins: [Antd] },
  });
}

describe('formulaBindingPanel', () => {
  it('已有映射分段位于前面并默认选中，仅在映射大于 0 时显示数量徽标', async () => {
    const wrapper = mountPanel();
    const segmented = wrapper.getComponent({ name: 'ASegmented' });
    expect(segmented.props('options').map((option: { value: string }) => option.value)).toEqual(['existing', 'create']);
    expect(segmented.props('value')).toBe('existing');
    expect(wrapper.find('[data-test="formula-existing"]').exists()).toBe(true);
    expect(wrapper.getComponent({ name: 'AEmpty' }).classes()).toContain('content-empty');
    expect(segmented.text()).toContain('已有映射');
    expect(wrapper.find('[data-test="existing-mapping-count"]').exists()).toBe(false);

    await wrapper.setProps({
      mappings: [
        {
          formulaVersionId: 'current',
          id: 'mapping',
          operationCode: 'mapping-op',
          parameterBindings: { amount: 'amount' },
          resultBindingId: 'result',
          status: 'ACTIVE',
          version: 1,
        },
      ],
    });
    expect(wrapper.get('[data-test="existing-mapping-count"]').text()).toBe('1');

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

    const versionSelect = wrapper.get('[data-test="formula-version-select"]').getComponent({ name: 'ASelect' });
    expect(versionSelect.props('options')).toEqual([
      expect.objectContaining({ label: '浓度', value: 'current' }),
      expect.objectContaining({ label: expect.stringContaining('预发布'), value: 'pre' }),
    ]);
    expect(versionSelect.props('options').map((item: { value: string }) => item.value)).not.toContain('historic');
  });

  it('按槽位和结果规则过滤候选，缺少必填绑定时禁用保存', async () => {
    const wrapper = mountPanel();
    wrapper.getComponent({ name: 'ASegmented' }).vm.$emit('update:value', 'create');
    await wrapper.vm.$nextTick();
    wrapper.get('[data-test="formula-version-select"]').getComponent({ name: 'ASelect' }).vm.$emit('update:value', 'current');
    await wrapper.vm.$nextTick();
    expect(wrapper.get('[data-test="formula-slot-amount"]').text()).toContain('样品量');
    expect(wrapper.get('[data-test="formula-save"]').attributes('disabled')).toBeDefined();
    expect(
      wrapper
        .get('[data-test="formula-slot-amount"]')
        .getComponent({ name: 'ASelect' })
        .props('options')
        .map((option: { value: string }) => option.value),
    ).toContain('amount');
    expect(
      wrapper
        .get('[data-test="formula-result"]')
        .getComponent({ name: 'ASelect' })
        .props('options')
        .map((option: { value: string }) => option.value),
    ).toEqual(expect.arrayContaining(['amount', 'result']));
    expect(wrapper.text()).not.toContain('引用');
  });

  it('升级已有映射时允许沿用该映射的当前结果字段', async () => {
    const wrapper = mount(FormulaBindingPanel, {
      props: {
        candidates,
        mappings: [
          {
            formulaVersionId: 'current',
            id: 'mapping',
            operationCode: 'mapping-op',
            parameterBindings: { amount: 'amount' },
            resultBindingId: 'result',
            status: 'ACTIVE',
            version: 1,
          },
        ],
        usedResultBindingIds: ['result'],
        versions: [
          {
            id: 'current',
            formulaCode: 'density',
            formulaName: '浓度',
            formulaEnabled: true,
            isCurrent: true,
            status: 'PUBLISHED',
            resultType: 'DECIMAL',
            slots: [{ code: 'amount', name: '样品量', required: true, type: 'DECIMAL' }],
          },
        ],
      },
      global: { plugins: [Antd] },
    });
    wrapper.getComponent({ name: 'ASegmented' }).vm.$emit('update:value', 'create');
    await wrapper.vm.$nextTick();
    wrapper.get('[data-test="formula-version-select"]').getComponent({ name: 'ASelect' }).vm.$emit('update:value', 'current');
    await wrapper.vm.$nextTick();
    expect(
      wrapper
        .get('[data-test="formula-result"]')
        .getComponent({ name: 'ASelect' })
        .props('options')
        .map((option: { value: string }) => option.value),
    ).not.toContain('result');

    wrapper.getComponent({ name: 'ASegmented' }).vm.$emit('update:value', 'existing');
    await wrapper.vm.$nextTick();
    expect(wrapper.get('[data-test="formula-existing"]').text()).toContain('浓度');
    expect(wrapper.get('[data-test="formula-existing"]').text()).not.toContain('mapping-op');
    await wrapper.get('[aria-label="公式映射操作"]').trigger('click');
    await wrapper.vm.$nextTick();
    const upgradeAction = document.body.querySelector('[data-test="formula-upgrade"]');
    expect(upgradeAction).not.toBeNull();
    await new DOMWrapper(upgradeAction as Element).trigger('click');

    expect(
      wrapper
        .get('[data-test="formula-result"]')
        .getComponent({ name: 'ASelect' })
        .props('options')
        .map((option: { value: string }) => option.value),
    ).toContain('result');
    expect(wrapper.get('[data-test="formula-save"]').text()).toContain('升级映射');
  });

  it('升级映射切换公式版本时只提交新版本的参数槽', async () => {
    const wrapper = mount(FormulaBindingPanel, {
      props: {
        candidates,
        mappings: [
          {
            formulaVersionId: 'current',
            id: 'mapping',
            operationCode: 'mapping-op',
            parameterBindings: { amount: 'amount' },
            resultBindingId: 'result',
            status: 'ACTIVE',
            version: 1,
          },
        ],
        versions: [
          {
            id: 'current',
            formulaCode: 'density',
            formulaName: '浓度',
            formulaEnabled: true,
            isCurrent: true,
            status: 'PUBLISHED',
            resultType: 'DECIMAL',
            slots: [{ code: 'amount', name: '样品量', required: true, type: 'DECIMAL' }],
          },
          {
            id: 'pre',
            formulaCode: 'density',
            formulaName: '浓度预发布',
            formulaEnabled: true,
            isCurrent: false,
            status: 'PRE_RELEASE',
            resultType: 'DECIMAL',
            slots: [{ code: 'volume', name: '体积', required: true, type: 'DECIMAL' }],
          },
        ],
      },
      global: { plugins: [Antd] },
    });
    wrapper.getComponent({ name: 'ASegmented' }).vm.$emit('update:value', 'existing');
    await wrapper.vm.$nextTick();
    await wrapper.get('[aria-label="公式映射操作"]').trigger('click');
    await wrapper.vm.$nextTick();
    await new DOMWrapper(document.body.querySelector('[data-test="formula-upgrade"]') as Element).trigger('click');

    wrapper.get('[data-test="formula-version-select"]').getComponent({ name: 'ASelect' }).vm.$emit('update:value', 'pre');
    await wrapper.vm.$nextTick();
    wrapper.get('[data-test="formula-slot-volume"]').getComponent({ name: 'ASelect' }).vm.$emit('update:value', 'amount');
    await wrapper.vm.$nextTick();
    await wrapper.get('[data-test="formula-save"]').trigger('click');

    expect(wrapper.emitted('upgrade')).toEqual([['mapping', { formulaVersionId: 'pre', parameterBindings: { volume: 'amount' }, resultBindingId: 'result' }]]);
  });

  it('离开升级流程后再进入新建映射时清空升级状态', async () => {
    const wrapper = mount(FormulaBindingPanel, {
      props: {
        candidates,
        mappings: [
          {
            formulaVersionId: 'current',
            id: 'mapping',
            operationCode: 'mapping-op',
            parameterBindings: { amount: 'amount' },
            resultBindingId: 'result',
            status: 'ACTIVE',
            version: 1,
          },
        ],
        versions: [
          {
            id: 'current',
            formulaCode: 'density',
            formulaName: '浓度',
            formulaEnabled: true,
            isCurrent: true,
            status: 'PUBLISHED',
            resultType: 'DECIMAL',
            slots: [{ code: 'amount', name: '样品量', required: true, type: 'DECIMAL' }],
          },
        ],
      },
      global: { plugins: [Antd] },
    });
    const segmented = wrapper.getComponent({ name: 'ASegmented' });
    segmented.vm.$emit('update:value', 'existing');
    await wrapper.vm.$nextTick();
    await wrapper.get('[aria-label="公式映射操作"]').trigger('click');
    await wrapper.vm.$nextTick();
    const upgradeActions = document.body.querySelectorAll('[data-test="formula-upgrade"]');
    await new DOMWrapper(upgradeActions[upgradeActions.length - 1] as Element).trigger('click');
    expect(wrapper.get('[data-test="formula-save"]').text()).toContain('升级映射');

    segmented.vm.$emit('update:value', 'existing');
    await wrapper.vm.$nextTick();
    segmented.vm.$emit('update:value', 'create');
    await wrapper.vm.$nextTick();

    expect(wrapper.text()).not.toContain('正在升级');
    expect(wrapper.get('[data-test="formula-save"]').text()).toContain('保存映射');
    expect(wrapper.get('[data-test="formula-version-select"]').getComponent({ name: 'ASelect' }).props('value')).toBeUndefined();
  });
});
