/*
 * Tencent is pleased to support the open source community by making TMagicEditor available.
 *
 * Copyright (C) 2025 Tencent.
 */
import { beforeEach, describe, expect, test, vi } from 'vitest';
import { defineComponent, h } from 'vue';
import { mount } from '@vue/test-utils';

import DisplayConds from '@editor/fields/DisplayConds.vue';

const dataSourceService = {
  getDataSourceById: vi.fn(),
};

vi.mock('@editor/hooks/use-services', () => ({
  useServices: () => ({ dataSourceService }),
}));

const { fieldTypeMock } = vi.hoisted(() => ({
  fieldTypeMock: vi.fn((_ds: any, names: string[]) => {
    const key = names?.[0];
    if (key === 'numField') return 'number';
    if (key === 'boolField') return 'boolean';
    if (key === 'nullField') return 'null';
    return 'string';
  }),
}));

vi.mock('@editor/utils', async () => {
  const actual = await vi.importActual<any>('@editor/utils');
  return {
    ...actual,
    getCascaderOptionsFromFields: vi.fn(() => [{ label: 'f1', value: 'f1' }]),
    getFieldType: fieldTypeMock,
  };
});

let capturedConfig: any = null;
vi.mock('@tmagic/form', async () => {
  const actual = await vi.importActual<any>('@tmagic/form');
  return {
    ...actual,
    filterFunction: vi.fn((_m: any, v: any) => (typeof v === 'function' ? v() : v)),
    MGroupList: defineComponent({
      name: 'MGroupList',
      props: ['config', 'name', 'disabled', 'model', 'lastValues', 'prop', 'size'],
      emits: ['change'],
      setup(props, { emit }) {
        capturedConfig = props.config;
        return () =>
          h('div', {
            class: 'fake-group-list',
            onClick: () => emit('change', [{ field: ['fa'], op: 'eq', value: 'a' }]),
          });
      },
    }),
  };
});

beforeEach(() => {
  vi.clearAllMocks();
  capturedConfig = null;
  dataSourceService.getDataSourceById.mockReturnValue({ fields: [{ name: 'a', type: 'string' }] });
});

describe('DisplayConds', () => {
  test('change 事件初始化数组', async () => {
    const model: any = {};
    const wrapper = mount(DisplayConds, {
      props: { config: { titlePrefix: 't', parentFields: [] }, model, name: 'conds' } as any,
    });
    await wrapper.find('.fake-group-list').trigger('click');
    expect(model.conds).toEqual([]);
    expect(wrapper.emitted('change')).toBeTruthy();
  });

  test('parentFields 不为空时使用 cascader', () => {
    mount(DisplayConds, {
      props: {
        config: { titlePrefix: 't', parentFields: ['ds1'] },
        model: {},
        name: 'conds',
      } as any,
    });
    const item = capturedConfig.items[0].items[0];
    expect(item.type).toBe('cascader');
    expect(item.options()).toEqual([{ label: 'f1', value: 'f1' }]);
  });

  test('parentFields 为空时使用 data-source-field-select', () => {
    mount(DisplayConds, {
      props: {
        config: { titlePrefix: 't', parentFields: [] },
        model: {},
        name: 'conds',
      } as any,
    });
    const item = capturedConfig.items[0].items[0];
    expect(item.type).toBe('data-source-field-select');
  });

  test('value 字段类型 - number', () => {
    mount(DisplayConds, {
      props: { config: { titlePrefix: 't', parentFields: ['ds1'] }, model: {}, name: 'conds' } as any,
    });
    const valueItem = capturedConfig.items[0].items[2].items[0];
    expect(valueItem.type(undefined, { model: { field: ['numField'] } })).toBe('number');
    expect(valueItem.type(undefined, { model: { field: ['boolField'] } })).toBe('select');
    expect(valueItem.type(undefined, { model: { field: ['nullField'] } })).toBe('display');
    expect(valueItem.type(undefined, { model: { field: ['anyField'] } })).toBe('text');
  });

  test('value display 函数', () => {
    mount(DisplayConds, {
      props: { config: { titlePrefix: 't', parentFields: [] }, model: {}, name: 'conds' } as any,
    });
    const valueItem = capturedConfig.items[0].items[2].items[0];
    expect(valueItem.display(undefined, { model: { op: 'eq' } })).toBe(true);
    expect(valueItem.display(undefined, { model: { op: 'between' } })).toBe(false);
    expect(valueItem.displayText(undefined, { model: { value: null } })).toBe('null');
    expect(valueItem.displayText(undefined, { model: { value: 'a' } })).toBe('a');
  });

  test('range display 函数', () => {
    mount(DisplayConds, {
      props: { config: { titlePrefix: 't', parentFields: [] }, model: {}, name: 'conds' } as any,
    });
    const rangeItem = capturedConfig.items[0].items[2].items[1];
    expect(rangeItem.display(undefined, { model: { op: 'between' } })).toBe(true);
    expect(rangeItem.display(undefined, { model: { op: 'eq' } })).toBe(false);
  });

  test('field onChange 转换 model.value 类型', () => {
    mount(DisplayConds, {
      props: { config: { titlePrefix: 't', parentFields: ['ds1'] }, model: {}, name: 'conds' } as any,
    });
    const item = capturedConfig.items[0].items[0];
    const m1: any = { value: '5' };
    item.onChange(undefined, ['numField'], { model: m1 });
    expect(m1.value).toBe(5);

    const m2: any = { value: '' };
    item.onChange(undefined, ['boolField'], { model: m2 });
    expect(m2.value).toBe(false);

    const m3: any = { value: 'x' };
    item.onChange(undefined, ['nullField'], { model: m3 });
    expect(m3.value).toBe(null);

    const m4: any = { value: 1 };
    item.onChange(undefined, ['strField'], { model: m4 });
    expect(m4.value).toBe('1');
  });

  test('cascader options 没有 ds 时返回空', () => {
    dataSourceService.getDataSourceById.mockReturnValue(null);
    mount(DisplayConds, {
      props: {
        config: { titlePrefix: 't', parentFields: ['ds1'] },
        model: {},
        name: 'conds',
      } as any,
    });
    const item = capturedConfig.items[0].items[0];
    expect(item.options()).toEqual([]);
  });
});
