<script lang="ts">
import { CaretDownOutlined, CaretUpOutlined } from '@ant-design/icons-vue';
import { type DslDefinition, DslDefinitionType } from '@oinone/kunlun-dsl';
import { translateValueByKey } from '@oinone/kunlun-engine';
import { DEFAULT_PREFIX } from '@oinone/kunlun-theme';
import {
  BooleanHelper,
  ButtonType,
  CastHelper,
  DEFAULT_COLS,
  FormLayout,
  IconPlacement,
  OioButton,
  OioForm,
  OioFormItem,
  OioFormProps,
  OioIcon,
  PropRecordHelper,
  StringHelper,
  useInjectOioDefaultFormContext,
  useProviderOioDefaultFormContext,
  ValidateTrigger
} from '@oinone/kunlun-vue-ui-antd';
import { DslRender, type DslRenderDefinition } from '@oinone/kunlun-vue-widget';
import { cloneDeep } from 'lodash-es';
import { computed, createVNode, defineComponent, ref, type VNode, vShow, withDirectives, withKeys } from 'vue';
import { InternalWidget, ResolveMode } from '../../tags';
import type { UserSearchPrefer } from '../../typing';
import { useProviderSearchPreferContext } from './context';
import SearchPrefer from './SearchPrefer.vue';
import { DefaultSearchProps } from './types';

function appendFieldDslDefinition(
  targets: DslDefinition[],
  widgets: DslDefinition[],
  expandSize: number,
  foldSize: number,
  cateFields?: string[]
): boolean {
  for (const widget of widgets) {
    const { dslNodeType } = widget;
    switch (dslNodeType as DslDefinitionType) {
      case DslDefinitionType.FIELD:
      case DslDefinitionType.ELEMENT: {
        if (BooleanHelper.isTrue(widget.invisible) || cateFields?.includes(widget.name)) {
          break;
        }
        const cloneWidget = cloneDeep(widget);
        cloneWidget.colSpan = Math.ceil(DEFAULT_COLS / (foldSize + 1));
        targets.push(cloneWidget);
        cloneWidget.subIndex = -targets.length;
        if (targets.length === expandSize + 1) {
          return true;
        }
        break;
      }
      case DslDefinitionType.PACK:
      case DslDefinitionType.SLOT: {
        const children = widget.widgets;
        if (children) {
          if (appendFieldDslDefinition(targets, children, expandSize, foldSize, cateFields)) {
            return true;
          }
        }
        break;
      }
    }
  }
  return false;
}

function appendCateFieldDslDefinition(
  targets: DslDefinition[],
  widgets: DslDefinition[],
  cateFields: string[]
): boolean {
  for (const widget of widgets) {
    const { dslNodeType } = widget;
    switch (dslNodeType as DslDefinitionType) {
      case DslDefinitionType.FIELD:
      case DslDefinitionType.ELEMENT: {
        if (cateFields.includes(widget.name)) {
          const cloneWidget = cloneDeep(widget);
          targets.push(cloneWidget);
        }
        break;
      }
      case DslDefinitionType.PACK:
      case DslDefinitionType.SLOT: {
        const children = widget.widgets;
        if (children) {
          if (appendCateFieldDslDefinition(targets, children, cateFields)) {
            return true;
          }
        }
        break;
      }
    }
  }
  return false;
}

function createSearchBar(
  isExpand: boolean,
  options: {
    hasExpandButton: boolean;
    showSearchPrefer: boolean;
    onSearch: () => void;
    onReset: () => void;
    onExpand: (expand: boolean) => void;
    translate?: (key: string) => string;
    preferProps: {
      selected: UserSearchPrefer | undefined;
      options: UserSearchPrefer[] | undefined;
      onLoad?: Function;
      onCreate?: Function;
      onUpdate?: Function;
      onRemove?: Function;
      onSelect?: Function;
      onUnselect?: Function;
    };
  }
): VNode[] {
  const children: VNode[] = [
    createVNode(
      OioButton,
      {
        type: ButtonType.primary,
        onClick: options.onSearch
      },
      { default: () => options.translate?.('kunlun.button.search') || translateValueByKey('搜索') }
    )
  ];
  if (options.showSearchPrefer) {
    children.push(createVNode(SearchPrefer, options.preferProps));
  }
  children.push(
    createVNode(
      OioButton,
      {
        type: ButtonType.link,
        onClick: options.onReset,
        class: 'reset-icon'
      },
      {
        default: () =>
          createVNode(OioIcon, { icon: 'oinone-15qingkong-1', size: '18', color: 'var(--oio-primary-color)' })
      }
    )
  );
  if (options.hasExpandButton) {
    let expandText: string;
    if (isExpand) {
      expandText = options.translate?.('kunlun.button.fold') || translateValueByKey('折叠');
    } else {
      expandText = options.translate?.('kunlun.button.expand') || translateValueByKey('展开');
    }
    children.push(
      createVNode(
        OioButton,
        {
          type: ButtonType.link,
          iconPlacement: IconPlacement.AFTER,
          icon: 'oinone-xiala',
          iconColor: 'var(--oio-primary-color)',
          onClick: options.onExpand
        },
        { default: () => expandText }
      )
    );
  }
  return [createVNode('div', { class: 'oio-default-search-action-bar' }, children)];
}

function createSearchBarCol(
  searchActionBar: VNode[],
  offset: number,
  invisible: boolean,
  foldSize: number,
  layout: FormLayout
) {
  return {
    internal: true,
    dslNodeType: DslDefinitionType.PACK,
    widgets: [],
    widget: InternalWidget.Col,
    span: DEFAULT_COLS / (foldSize + 1),
    offset,
    invisible,
    allInvisible: false,
    class: `${DEFAULT_PREFIX}-col-${layout}`,
    __slots: { default: () => searchActionBar }
  } as DslRenderDefinition;
}

export default defineComponent({
  name: 'DefaultSearch',
  components: {
    OioForm,
    OioFormItem,
    SearchPrefer,
    CaretDownOutlined,
    CaretUpOutlined
  },
  inheritAttrs: false,
  props: {
    ...DefaultSearchProps
  },
  setup(props, context) {
    const origin = ref<HTMLElement>();
    const formContext = useInjectOioDefaultFormContext();

    const onExpand = () => {
      props.onExpand?.(!props.isExpand);
    };

    const onSearch = () => {
      props.onSearch?.();
    };

    const onReset = () => {
      props.onReset?.();
    };

    useProviderOioDefaultFormContext({
      ...formContext,
      getTriggerContainer: (triggerNode) => {
        if (formContext.getTriggerContainer) {
          return formContext.getTriggerContainer(triggerNode);
        }
        if (origin.value) {
          return origin.value;
        }
        return triggerNode.parentNode || document.body;
      }
    });

    useProviderSearchPreferContext({
      selected: computed(() => props.selectedPrefer),
      options: computed(() => props.searchPreferOptions)
    });

    return {
      origin,
      onExpand,
      onSearch,
      onReset
    };
  },
  render() {
    const {
      $slots,

      template,
      cateFields,
      showTopCateAll,
      showSecondCateAll,
      topCateJustify,
      disabledExpand,
      invisibleSearch,
      foldSize,
      showSearchPrefer,
      isExpand,
      layout,

      translate,
      selectedPrefer,
      searchPreferOptions,
      onLoadSearchPreferOptions,
      onCreateSearchPrefer,
      onUpdateSearchPrefer,
      onRemoveSearchPrefer,
      onSelectSearchPrefer,
      onUnselectSearchPrefer,

      onSearch,
      onReset,
      onExpand
    } = this;

    const defaultChildren: VNode[] = [];
    let invisible = false;
    let hasExpandButton = false;

    if (template) {
      const { widgets } = template;
      if (widgets && widgets.length) {
        const cateWidgets = [] as DslDefinition[];
        if (cateFields?.length) {
          appendCateFieldDslDefinition(cateWidgets, widgets, cateFields);
          if (cateWidgets.length) {
            defaultChildren.push(
              DslRender.render({
                cateFields,
                dslNodeType: DslDefinitionType.ELEMENT,
                widget: 'SearchTab',
                widgets: cateWidgets,
                showTopCateAll,
                showSecondCateAll,
                topCateJustify
              })!
            );
          }
        }

        let fields: DslDefinition[] = [];
        if (!disabledExpand) {
          const finalExpandSize = invisibleSearch ? foldSize + 1 : foldSize;
          appendFieldDslDefinition(fields, widgets, finalExpandSize, foldSize, cateFields);
          if (fields.length) {
            hasExpandButton = fields.length > finalExpandSize;
            if (hasExpandButton) {
              fields = fields.slice(0, finalExpandSize);
            }
            if (!invisibleSearch) {
              const searchActionBar: VNode[] = createSearchBar(false, {
                hasExpandButton,
                showSearchPrefer,
                onSearch,
                onReset,
                onExpand,
                translate,
                preferProps: {
                  selected: selectedPrefer,
                  options: searchPreferOptions,
                  onLoad: onLoadSearchPreferOptions,
                  onCreate: onCreateSearchPrefer,
                  onUpdate: onUpdateSearchPrefer,
                  onRemove: onRemoveSearchPrefer,
                  onSelect: onSelectSearchPrefer,
                  onUnselect: onUnselectSearchPrefer
                }
              });
              invisible = !fields.length;

              const size = layout === FormLayout.vertical ? foldSize + 1 : foldSize;
              const searchBarCol = createSearchBarCol(
                searchActionBar,
                (foldSize - fields.length) * (DEFAULT_COLS / (foldSize + 1)),
                invisible,
                size,
                layout
              );
              fields.push(searchBarCol);
            }
          } else {
            hasExpandButton = false;
            fields = widgets;
          }
          defaultChildren.push(
            withDirectives(
              DslRender.render({
                internal: true,
                dslNodeType: DslDefinitionType.PACK,
                widgets: fields,
                widget: InternalWidget.Row,
                cols: DEFAULT_COLS,
                resolveOptions: {
                  mode: ResolveMode.NORMAL
                }
              })!,
              [[vShow, !isExpand]]
            )
          );
        }
      }
    }

    if (hasExpandButton || disabledExpand) {
      const foldChildren = PropRecordHelper.collectionSlots($slots, [
        {
          origin: 'default',
          isNotNull: true
        }
      ])
        .default()
        .filter((VNode) => !cateFields?.includes(VNode.props?.dslDefinition?.name));

      const foldVNodes: VNode[] = [
        DslRender.render(
          {
            ...(template || {}),
            internal: true,
            dslNodeType: DslDefinitionType.PACK,
            widgets: [],
            widget: InternalWidget.Row,
            resolveOptions: {
              mode: ResolveMode.NORMAL
            }
          },
          undefined,
          { default: () => foldChildren }
        )!
      ];
      if (!invisibleSearch) {
        const searchActionBar: VNode[] = createSearchBar(true, {
          hasExpandButton,
          showSearchPrefer,
          onSearch,
          onReset,
          onExpand,
          translate,
          preferProps: {
            selected: selectedPrefer,
            options: searchPreferOptions,
            onLoad: onLoadSearchPreferOptions,
            onCreate: onCreateSearchPrefer,
            onUpdate: onUpdateSearchPrefer,
            onRemove: onRemoveSearchPrefer,
            onSelect: onSelectSearchPrefer,
            onUnselect: onUnselectSearchPrefer
          }
        });

        const defaultOffset = foldSize * (DEFAULT_COLS / (foldSize + 1));
        const offset = layout === FormLayout.vertical ? Math.floor(defaultOffset - 1) : defaultOffset;
        const size = layout === FormLayout.vertical ? foldSize - 1 : foldSize;
        const searchBarCol = createSearchBarCol(
          searchActionBar,
          offset, // 预留高级搜索区域
          invisible,
          size,
          layout
        );
        foldVNodes.push(
          DslRender.render({
            internal: true,
            dslNodeType: DslDefinitionType.PACK,
            widgets: [searchBarCol],
            widget: InternalWidget.Row,
            cols: DEFAULT_COLS,
            resolveOptions: {
              mode: ResolveMode.NORMAL
            }
          })!
        );
      }
      let foldContent = createVNode('div', { class: `${DEFAULT_PREFIX}-default-search-fold-content` }, foldVNodes);
      if (!disabledExpand) {
        foldContent = withDirectives(foldContent, [[vShow, isExpand]]);
      }
      defaultChildren.push(foldContent);
    }

    const classList = [
      `${DEFAULT_PREFIX}-default-form`,
      `${DEFAULT_PREFIX}-default-search`,
      `${DEFAULT_PREFIX}-default-${layout}-search`
    ];
    if (this.isExpand) {
      classList.push(`${DEFAULT_PREFIX}-default-search-expand`);
    }

    return withDirectives(
      createVNode(
        'div',
        {
          ...PropRecordHelper.collectionBasicProps(this.$attrs, classList),
          ref: 'origin'
        },
        [
          createVNode(
            OioForm,
            {
              ...PropRecordHelper.convert(OioFormProps, CastHelper.cast(this)),
              layout,
              wrapperClassName: StringHelper.append(
                [`${DEFAULT_PREFIX}-default-form-wrapper`, `${DEFAULT_PREFIX}-default-search-wrapper`],
                this.wrapperClassName
              ).join(' '),
              data: this.formData,
              validateTrigger: ValidateTrigger.BLUR,
              onKeyup: withKeys(this.onSearch, ['enter'])
            },
            {
              default: () => defaultChildren
            }
          )
        ]
      ),
      [[vShow, !this.invisible]]
    );
  }
});
</script>
