import { mount, shallowMount } from '@vue/test-utils';
import { nextTick, reactive, watch } from 'vue';

import { Input as AInput } from 'ant-design-vue';
import { describe, expect, it, vi } from 'vitest';

import ParameterTable from '../ParameterTable.vue';
import tableSource from '../ParameterTable.vue?raw';

const tableState = vi.hoisted(() => ({ config: undefined as any }));

vi.mock('@jnpf/ui/vxeTable', () => ({
  BasicVxeTable: {
    name: 'BasicVxeTable',
    props: ['dataSource'],
    template:
      '<div><slot v-if="dataSource?.length" name="canshuMingcheng" :record="dataSource[0]" /><slot v-if="dataSource?.length" name="shujuLeixing" :record="dataSource[0]" /><slot v-if="dataSource?.length" name="danwei" :record="dataSource[0]" /></div>',
  },
  useVxeTable: (config: any) => {
    tableState.config = config;
    return [vi.fn()];
  },
}));

describe('eLN formula parameter table', () => {
  it('only allows draft slots to be edited or removed', () => {
    const wrapper = mount(ParameterTable, {
      props: { modelValue: [], readonly: true, status: 'PRE_RELEASE' },
      global: {
        stubs: {
          'a-alert': { props: ['message'], template: '<span>{{ message }}</span>' },
          'a-button': true,
          'a-input': true,
          'a-input-number': true,
          'a-select': true,
          'a-switch': true,
          'a-tag': true,
        },
      },
    });
    expect(wrapper.text()).toContain('集合参数仅支持映射重复区域的数值字段，不支持普通字段或逐行公式');
    expect(tableSource).toContain("status === 'DRAFT'");
    expect(tableSource).toContain('canshuBianma');
    expect(tableSource).toContain('DECIMAL_LIST');
  });

  it('adds only business properties and leaves the generated code to the backend', () => {
    expect(tableSource).toContain("canshuMingcheng: ''");
    expect(tableSource).not.toContain("canshuBianma: ''");
  });

  it('uses a stable client key for unsaved parameter rows', () => {
    expect(tableSource).toContain('row._clientKey || row.id');
    expect(tableSource).toContain('_clientKey:');
  });

  it('uses a stable height when embedded in a formula modal', () => {
    shallowMount(ParameterTable, {
      props: { modelValue: [], status: 'DRAFT' },
      global: { stubs: { 'a-alert': true, 'a-button': true, 'a-input': true, 'a-input-number': true, 'a-select': true, 'a-switch': true } },
    });

    expect(tableState.config.height).toBe(220);
  });

  it('uses its own stable height when it replaces the formula workspace', () => {
    const wrapper = shallowMount(ParameterTable, {
      props: { fullHeight: true, modelValue: [], status: 'DRAFT' },
      global: { stubs: { 'a-alert': true, 'a-button': true, 'a-input': true, 'a-input-number': true, 'a-select': true, 'a-switch': true } },
    });

    expect(typeof tableState.config.height).toBe('number');
    expect(tableState.config.height).toBeGreaterThanOrEqual(360);
    expect(wrapper.classes()).toContain('is-full-height');
  });

  it('maps parameter type option labels and values for the native select', () => {
    const wrapper = mount(ParameterTable, {
      props: {
        modelValue: [{ canshuBianma: 'amount', canshuMingcheng: '含量', paixu: 1, shifouBitian: 1, shujuLeixing: 'DECIMAL' }],
        status: 'DRAFT',
      },
      global: {
        stubs: {
          'a-alert': true,
          'a-button': true,
          'a-input': true,
          'a-input-number': true,
          'a-select': { name: 'ASelect', props: ['fieldNames', 'options', 'value'], template: '<div />' },
          'a-switch': true,
        },
      },
    });

    const typeSelect = wrapper.findComponent({ name: 'ASelect' });
    expect(typeSelect.props('fieldNames')).toEqual({ label: 'fullName', value: 'id' });
    expect(typeSelect.props('options')).toContainEqual({ fullName: '数值', id: 'DECIMAL' });
  });

  it('provides prompts for editable parameter fields and enough room for sorting', () => {
    shallowMount(ParameterTable, {
      props: { modelValue: [], status: 'DRAFT' },
      global: { stubs: { 'a-alert': true, 'a-button': true, 'a-input': true, 'a-input-number': true, 'a-select': true, 'a-switch': true } },
    });

    expect(tableSource).toContain('placeholder="请输入参数名称"');
    expect(tableSource).toContain('placeholder="请选择类型"');
    expect(tableSource).toContain('placeholder="请输入单位"');
    expect(tableSource).toContain('placeholder="请输入排序"');
    expect(tableState.config.columns.find((column: any) => column.dataIndex === 'paixu').width).toBe(110);
  });

  it('uses a compact action header without adding space below the notice', () => {
    expect(tableSource).not.toContain('<span>参数槽</span>');
    expect(tableSource).toContain('<a-button v-if="editable" type="default"');
    expect(tableSource).toContain('<a-alert banner class="parameter-table__notice"');
    expect(tableSource).toMatch(/\.parameter-table__notice\s*\{[^}]*margin-top: 8px/);
    expect(tableSource).not.toMatch(/\.parameter-table__notice\s*\{[^}]*margin-bottom:/);
  });

  it('updates a unit without triggering a reactive table refresh', async () => {
    const parameter = reactive({
      _clientKey: 'row-1',
      canshuMingcheng: '含量',
      danwei: undefined as string | undefined,
      paixu: 1,
      shifouBitian: 1 as const,
      shujuLeixing: 'DECIMAL' as const,
    });
    let reactiveUpdates = 0;
    watch(
      () => parameter.danwei,
      () => reactiveUpdates++,
    );
    const wrapper = mount(ParameterTable, {
      props: { modelValue: [parameter], status: 'DRAFT' },
      global: {
        stubs: {
          'a-alert': true,
          'a-button': true,
          'a-input': { name: 'AInput', props: ['value'], template: '<input />' },
          'a-input-number': true,
          'a-select': true,
          'a-switch': true,
        },
      },
    });

    const unitInput = wrapper.findAllComponents({ name: 'AInput' }).find((input) => input.props('value') === undefined)!;
    unitInput.vm.$emit('update:value', 'mg/mL');
    await nextTick();

    expect(unitInput.props('value')).toBe('mg/mL');
    expect(parameter.danwei).toBe('mg/mL');
    expect(reactiveUpdates).toBe(0);
    expect(wrapper.emitted('update:modelValue')).toBeUndefined();
  });

  it('updates a parameter name without triggering a reactive table refresh', async () => {
    const parameter = reactive({
      _clientKey: 'row-1',
      canshuMingcheng: '含量',
      danwei: undefined as string | undefined,
      paixu: 1,
      shifouBitian: 1 as const,
      shujuLeixing: 'DECIMAL' as const,
    });
    let reactiveUpdates = 0;
    watch(
      () => parameter.canshuMingcheng,
      () => reactiveUpdates++,
    );
    const wrapper = mount(ParameterTable, {
      props: { modelValue: [parameter], status: 'DRAFT' },
      global: {
        stubs: {
          'a-alert': true,
          'a-button': true,
          'a-input': { name: 'AInput', props: ['value'], template: '<input />' },
          'a-input-number': true,
          'a-select': true,
          'a-switch': true,
        },
      },
    });

    const nameInput = wrapper.findAllComponents({ name: 'AInput' }).find((input) => input.props('value') === '含量')!;
    nameInput.vm.$emit('update:value', '水分');
    await nextTick();

    expect(nameInput.props('value')).toBe('水分');
    expect(parameter.canshuMingcheng).toBe('水分');
    expect(reactiveUpdates).toBe(0);
    expect(wrapper.emitted('update:modelValue')).toBeUndefined();
  });

  it('keeps real Ant inputs interactive while synchronizing submitted text values', async () => {
    const parameter = reactive({
      _clientKey: 'row-1',
      canshuMingcheng: '',
      danwei: undefined as string | undefined,
      paixu: 1,
      shifouBitian: 1 as const,
      shujuLeixing: 'DECIMAL' as const,
    });
    const wrapper = mount(ParameterTable, {
      props: { modelValue: [parameter], status: 'DRAFT' },
      global: {
        components: { AInput },
        stubs: {
          'a-alert': true,
          'a-button': true,
          'a-input-number': true,
          'a-select': true,
          'a-switch': true,
        },
      },
    });

    const nameInput = wrapper.find('input[placeholder="请输入参数名称"]');
    const unitInput = wrapper.find('input[placeholder="请输入单位"]');
    await nameInput.setValue('水分');
    await unitInput.setValue('mg/mL');

    expect((nameInput.element as HTMLInputElement).value).toBe('水分');
    expect((unitInput.element as HTMLInputElement).value).toBe('mg/mL');
    expect(parameter.canshuMingcheng).toBe('水分');
    expect(parameter.danwei).toBe('mg/mL');
  });
});
