import type { ComputedRef } from 'vue';

import type {
  VxeGridPropTypes,
  VxeTableGridOptions,
} from '@vben/plugins/vxe-table';
import type { Recordable } from '@vben/types';

import type { CheckedType, TableSwitchProps } from '#/components/table';

import { computed, h, isRef } from 'vue';

import { useAccess } from '@vben/access';
import { IconifyIcon } from '@vben/icons';
import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table';
import { get, isFunction, isString } from '@vben/utils';

import { objectOmit } from '@vueuse/core';
import { Button, Image, Popconfirm, Tag } from 'ant-design-vue';
import { isArray } from 'lodash-es';

import { TableSwitch } from '#/components/table';

import { useVbenForm } from './form';

const { hasAccessByCodes } = useAccess();

setupVbenVxeTable({
  configVxeTable: (vxeUI) => {
    vxeUI.setConfig({
      grid: {
        align: 'center',
        // https://vxetable.cn/#/component/table/base/border
        border: 'inner',
        columnConfig: {
          resizable: true,
        },
        minHeight: 180,
        formConfig: {
          // 全局禁用vxe-table的表单配置，使用formOptions
          enabled: false,
        },
        proxyConfig: {
          autoLoad: true,
          response: {
            result: 'data',
            total: 'totalCount',
            list: 'data',
          },
          showActiveMsg: true,
          showResponseMsg: false,
        },
        pagerConfig: {
          // 默认条数
          pageSize: 10,
          // 分页可选条数
          pageSizes: [10, 20, 30, 40, 50],
        },
        rowConfig: {
          // 鼠标移入行显示 hover 样式
          isHover: false,
          // 点击行高亮
          isCurrent: true,
        },
        // 右上角工具栏
        toolbarConfig: {
          // 自定义列
          // 自定义列
          custom: true,
          customOptions: {
            icon: 'vxe-icon-setting',
          },
          // 最大化
          zoom: true,
          // 刷新
          refresh: true,
          refreshOptions: {
            // 默认为reload 修改为在当前页刷新
            code: 'query',
          },
        },
        customConfig: {
          // 表格右上角自定义列配置 是否保存到localStorage
          // 必须存在id参数才能使用
          storage: false,
        },
        round: true,
        showOverflow: true,
        size: 'small',
      } as VxeTableGridOptions,
    });

    // 表格配置项可以用 cellRender: { name: 'CellImage' },
    vxeUI.renderer.add('CellImage', {
      renderTableDefault(_renderOpts, params) {
        const { column, row } = params;
        return h(Image, { src: row[column.field] });
      },
    });

    // 表格配置项可以用 cellRender: { name: 'CellLink' },
    vxeUI.renderer.add('CellLink', {
      renderTableDefault(renderOpts) {
        const { props } = renderOpts;
        return h(
          Button,
          { size: 'small', type: 'link' },
          { default: () => props?.text },
        );
      },
    });

    // 单元格渲染： Tag
    vxeUI.renderer.add('CellTag', {
      renderTableDefault({ options, props }, { column, row }) {
        const value = get(row, column.field);
        const computeFlag = options && options[0] && isRef(options[0]);

        function renderTagItem(itemValue: any) {
          let tagItem: any;
          if (computeFlag) {
            tagItem = computed(() => {
              const _tagItem = (options[0] as ComputedRef).value.find(
                (item: any) => item.value === itemValue,
              );
              return _tagItem;
            });
            return h(
              Tag,
              {
                ...props,
                ...objectOmit(tagItem.value ?? {}, ['label']),
              },
              { default: () => tagItem.value?.label ?? value },
            );
          } else {
            const tagOptions = options ?? [
              { color: 'success', label: '已启用', value: 1 },
              { color: 'error', label: '已禁用', value: 0 },
            ];
            tagItem = tagOptions.find((item) => item.value === itemValue);
            return h(
              Tag,
              {
                ...props,
                ...objectOmit(tagItem ?? {}, ['label']),
              },
              { default: () => tagItem?.label ?? value },
            );
          }
        }
        if (isArray(value)) {
          const tags = value.map((item, index) => {
            return h('div', { key: index }, renderTagItem(item));
          });
          return h(
            'div',
            {
              class: 'flex flex-col',
              style: { gap: '4px' },
            },
            tags,
          );
        } else {
          return renderTagItem(value);
        }
      },
    });

    vxeUI.renderer.add('CellSwitch', {
      renderTableDefault({ props }, { column, row }) {
        // const loadingKey = `__loading_${column.field}`;
        const finallyProps = {
          // checkedText: '启用',
          // unCheckedText: '禁用',
          checkedValue: 1,
          unCheckedValue: 0,
          confirm: false,
          confirmText: undefined,
          disabled: false,
          api: (_newVal: CheckedType) => Promise.resolve(),
          value: row[column.field],
          ...props,
          // onReload: () => Promise<void>,
          // 'onUpdate:value': () => Promise<void>,
          // ...props,
          // checked: row[column.field],
          // loading: row[loadingKey] ?? false,
          // 'onUpdate:checked': onChange,
        } satisfies Partial<TableSwitchProps>;
        if (props && props.disabled && isFunction(props.disabled)) {
          finallyProps.disabled = props.disabled(row);
        }
        if (props && props.api && isFunction(props.api)) {
          finallyProps.api = (newVal: CheckedType) => {
            row[column.field] = newVal;
            return props.api(row);
          };
        }
        return h(TableSwitch, finallyProps);
      },
    });

    /**
     * 注册表格的操作按钮渲染器
     */
    vxeUI.renderer.add('CellOperation', {
      renderTableDefault({ attrs, options, props }, { column, row }) {
        const defaultProps = { size: 'small', type: 'link', ...props };
        let align = 'end';
        switch (column.align) {
          case 'center': {
            align = 'center';
            break;
          }
          case 'left': {
            align = 'start';
            break;
          }
          default: {
            align = 'end';
            break;
          }
        }
        const presets: Recordable<Recordable<any>> = {
          delete: {
            danger: true,
            text: '删除',
          },
          edit: {
            text: '修改',
          },
        };
        const operations: Array<Recordable<any>> = (
          options || ['edit', 'delete']
        )
          .map((opt) => {
            if (isString(opt)) {
              return presets[opt]
                ? { code: opt, ...presets[opt], ...defaultProps }
                : {
                    code: opt,
                    text: opt,
                    ...defaultProps,
                  };
            } else {
              return { ...defaultProps, ...presets[opt.code], ...opt };
            }
          })
          .map((opt) => {
            const optBtn: Recordable<any> = {};
            Object.keys(opt).forEach((key) => {
              optBtn[key] = isFunction(opt[key]) ? opt[key](row) : opt[key];
            });
            return optBtn;
          })
          .filter((opt) => opt.show !== false);

        function renderBtn(opt: Recordable<any>, listen = true) {
          if (opt.accessCode) {
            const hasAccess = hasAccessByCodes(opt.accessCode as string[]);
            if (!hasAccess) return null;
          }

          return h(
            Button,
            {
              ...props,
              ...opt,
              icon: undefined,
              onClick: listen
                ? () =>
                    attrs?.onClick?.({
                      code: opt.code,
                      row,
                    })
                : undefined,
            },
            {
              default: () => {
                const content = [];
                if (opt.icon) {
                  content.push(
                    h(IconifyIcon, { class: 'size-5', icon: opt.icon }),
                  );
                }
                content.push(opt.text);
                return content;
              },
            },
          );
        }

        function renderConfirm(opt: Recordable<any>) {
          if (opt.accessCode) {
            const hasAccess = hasAccessByCodes(opt.accessCode as string[]);
            if (!hasAccess) return null;
          }

          let viewportWrapper: HTMLElement | null = null;
          return h(
            Popconfirm,
            {
              /**
               * 当popconfirm用在固定列中时，将固定列作为弹窗的容器时可能会因为固定列较窄而无法容纳弹窗
               * 将表格主体区域作为弹窗容器时又会因为固定列的层级较高而遮挡弹窗
               * 将body或者表格视口区域作为弹窗容器时又会导致弹窗无法跟随表格滚动。
               * 鉴于以上各种情况，一种折中的解决方案是弹出层展示时，禁止操作表格的滚动条。
               * 这样既解决了弹窗的遮挡问题，又不至于让弹窗随着表格的滚动而跑出视口区域。
               */
              getPopupContainer(el) {
                viewportWrapper = el.closest('.vxe-table--viewport-wrapper');
                return document.body;
              },
              placement: 'topLeft',
              title: `删除${attrs?.nameTitle}`,
              ...props,
              ...opt,
              icon: undefined,
              onOpenChange: (open: boolean) => {
                // 当弹窗打开时，禁止表格的滚动
                if (open) {
                  viewportWrapper?.style.setProperty('pointer-events', 'none');
                } else {
                  viewportWrapper?.style.removeProperty('pointer-events');
                }
              },
              onConfirm: () => {
                attrs?.onClick?.({
                  code: opt.code,
                  row,
                });
              },
            },
            {
              default: () => renderBtn({ ...opt }, false),
              description: () =>
                h(
                  'div',
                  { class: 'truncate' },
                  `确定删除${row[attrs?.nameField || 'name']}吗？`,
                ),
            },
          );
        }

        const btns = operations.map((opt) =>
          opt.code === 'delete' ? renderConfirm(opt) : renderBtn(opt),
        );
        return h(
          'div',
          {
            class: 'flex table-operations',
            style: { justifyContent: align },
          },
          btns,
        );
      },
    });

    // 这里可以自行扩展 vxe-table 的全局配置，比如自定义格式化
    // vxeUI.formats.add
  },
  useVbenForm,
});

export { useVbenVxeGrid };

export type OnActionClickParams<T = Recordable<any>> = {
  code: string;
  row: T;
};
export type OnActionClickFn<T = Recordable<any>> = (
  params: OnActionClickParams<T>,
) => void;

export type * from '@vben/plugins/vxe-table';

/**
 * 判断vxe-table的复选框是否选中
 * @param tableApi api
 * @returns boolean
 */
export function vxeCheckboxChecked(
  tableApi: ReturnType<typeof useVbenVxeGrid>[1],
) {
  return tableApi?.grid?.getCheckboxRecords?.()?.length > 0;
}

/**
 * 通用的 排序参数添加到请求参数中
 * @param params 请求参数
 * @param sortList vxe-table的排序参数
 */
export function addSortParams(
  params: Record<string, any>,
  sortList: VxeGridPropTypes.ProxyAjaxQuerySortCheckedParams[],
) {
  // 这里是排序取消 length为0 就不添加参数了
  if (sortList.length === 0) {
    return;
  }
  // 支持单/多字段排序
  const orderByColumn = sortList.map((item) => item.field).join(',');
  const isAsc = sortList.map((item) => item.order).join(',');
  params.orderByColumn = orderByColumn;
  params.isAsc = isAsc;
}
