<template>
  <div>
    <template v-for="item in topButtonList" :key="item.key">
      <a-button
        :type="item.style"
        @click="customClick(item)"
        :disabled="disabled"
        class="mr-2 mb-2"
      >
        <Icon :icon="item.icon" />
        {{ t(item.label) }}
      </a-button>
    </template>
    <a-table
      :id="'table' + madomkey"
      :row-selection="rowSelection"
      :columns="columns"
      :bordered="showFormBorder"
      :pagination="false"
      :data-source="data"
      :scroll="{ x: 'max-content', y: height }"
      @resize-column="handleResizeColumn"
    >
      <template #bodyCell="{ column, record, index }">
        <template v-if="column.key !== 'action'">
          <template v-if="column.key === 'index'">
            {{ index + 1 }}
          </template>
          <template v-else-if="column.isEdit">
            <div
              class="ant-table-cell-ellipsis"
              :title="record[column.dataIndex]"
              :style="
                column.width
                  ? executeListStyle(record, column?.componentProps?.listStyle) +
                    `;width: ${isNumber(column.width) ? column.width + 'px' : column.width}`
                  : executeListStyle(record, column?.componentProps?.listStyle)
              "
            >
              {{ record[column.dataIndex] }}</div
            >
          </template>
          <FormItem
            :name="[subFormList, subFormIndex, mainKey, index, column.dataIndex]"
            :rules="rules(column, record, index)"
            :validateTrigger="['blur', 'change']"
            v-else-if="!column.isEdit"
          >
            <!---如果是checked一类的组件-->
            <template v-if="checkedValueComponents.includes(column.componentType)">
              <component
                :is="componentMap.get(column.componentType)"
                :bordered="showComponentBorder"
                v-bind="getComponentsProps(column, record, index)"
                v-model:checked="record[column.dataIndex]"
                :style="executeListStyle(record, column?.componentProps?.listStyle)"
              />
            </template>
            <!---如果是RangePicker组件-->
            <template
              v-else-if="
                column.componentType === 'RangePicker' || column.componentType === 'TimeRangePicker'
              "
            >
              <component
                :is="componentMap.get(column.componentType)"
                :bordered="showComponentBorder"
                v-bind="getComponentsProps(column, record, index)"
                v-model:startField="column.dataIndex.split(',')[0]"
                v-model:endField="column.dataIndex.split(',')[1]"
                v-model:value="record[column.dataIndex]"
                v-model:record="data[index]"
                :mainKey="mainKey"
                :style="executeListStyle(record, column?.componentProps?.listStyle)"
              />
            </template>
            <template v-else-if="column.componentType === 'RichTextEditor'">
              <component
                :is="componentMap.get('TableEditor')"
                :bordered="showComponentBorder"
                v-bind="getComponentsProps(column, record, index)"
                v-model:value="record[column.dataIndex]"
                :mainKey="mainKey"
              />
            </template>
            <!---如果是渲染函数组件-->
            <template v-else-if="column.componentType === 'Render'">
              <component
                :bordered="showComponentBorder"
                :is="
                  column.render({
                    model: record,
                    field: column.dataIndex,
                    rules: column.rules,

                    componentProps: getComponentsProps(column, record, index),
                  })
                "
              />
            </template>
            <template v-else-if="column.componentType === 'XjrCustomModal'">
              <a-button type="primary" @click="showModal(column, record, index)">{{
                column.title
              }}</a-button>
            </template>
            <template v-else-if="column.key !== 'index'">
              <component
                :is="componentMap.get(column.componentType)"
                :bordered="showComponentBorder"
                v-bind="getComponentsProps(column, record, index)"
                :index="index"
                :mainKey="mainKey"
                v-model:value="record[column.dataIndex]"
                :style="executeListStyle(record, column?.componentProps?.listStyle)"
              />
            </template>
          </FormItem>
        </template>
        <template v-if="column.key === 'action' && !disabled">
          <template v-if="buttonList && buttonList.length > 0">
            <template v-for="item in buttonList" :key="item.key">
              <a-tooltip v-if="item.icon">
                <template #title> {{ t(item.label) }}</template>
                <Icon
                  :icon="item.icon"
                  :style="{ marginRight: '10px' }"
                  @click="customClick(item, record, index)"
                />
              </a-tooltip>
              <a-button
                @click="customClick(item, record, index)"
                v-else-if="item.label && !item.icon"
                type="link"
                size="small"
                :style="{
                  marginRight: '10px',
                  padding: 0,
                  border: 0,
                }"
                >{{ t(item.label) }}</a-button
              >
            </template>
          </template>
          <MinusCircleOutlined @click="remove(index)" style="padding-bottom: 20px" />
        </template>
        <div class="resize-handle" v-if="rowResize"></div>
      </template>
    </a-table>
    <a-button type="dashed" block @click="add" v-if="!disabled">
      <PlusOutlined />
      {{ t('新增') }}
    </a-button>
    <TableCustomModal
      @register="registerModal"
      @confirm="
        (val) => {
          data[curRecord] = val;
        }
      "
    />
  </div>
</template>
<script lang="ts" setup>
  import { PlusOutlined, MinusCircleOutlined } from '@ant-design/icons-vue';
  import { Form } from 'ant-design-vue';
  import { inject, onMounted, ref, unref, watch, nextTick } from 'vue';
  import { SubFormColumn } from '../types';
  import { componentMap } from '../componentMap';
  import { DicDataComponents, checkedValueComponents, staticDataComponents } from '../helper';
  import { isFunction, cloneDeep, isBoolean, upperFirst, isNumber } from 'lodash-es';
  import { deepMerge } from '/@/utils';
  import { useI18n } from '/@/hooks/web/useI18n';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { FormActionType } from '/@/components/Form/src/types/form';
  import type { TableProps } from 'ant-design-vue';
  import { camelCaseString } from '/@/utils/event/design';
  import { executeListStyle } from '/@/hooks/web/useListStyle';
  import { executeCurFormEvent } from '/@/utils/event/data';
  import { Icon } from '/@/components/Icon';
  import TableCustomModal from './TableCustomModal.vue';
  import { useModal } from '/@/components/Modal';
  import { ExecuteType } from '/@/enums/desktop';
  const { t } = useI18n();
  // 用于包裹弹窗的form组件 因为一个FormItem 只能收集一个表单组件  所以弹窗的form 必须排除
  // const FormItemRest = Form.ItemRest;
  const FormItem = Form.Item;

  const emit = defineEmits(['change', 'update:value', 'add', 'delete', 'select', 'load']);

  const props = defineProps({
    /**
     * 如果是编辑状态 默认现实的值
     */
    value: { type: Array as PropType<Recordable[]>, default: () => [] },
    /**
     * 需要绑定主表的字段  用于验证  必填
     */
    mainKey: { type: String, required: true },
    /**
     * 子表单配置
     */
    columns: {
      type: Array as PropType<SubFormColumn[]>,
      required: true,
    },
    /**
     * 是否禁用所有组件
     */
    disabled: {
      type: Boolean,
      default: false,
    },
    //是否显示表格边框
    showFormBorder: Boolean,
    //是否显示组件边框
    showComponentBorder: Boolean,
    //是否展示序号
    showIndex: Boolean,
    //add before hooks
    addBefore: Function,
    //add after hooks
    addAfter: Function,
    formApi: {
      type: Object as PropType<FormActionType>,
    },
    subFormIndex: Number,
    subFormList: String,
    rowSpan: String,
    //表格列宽配置
    widths: Array,
    //表格行高可拖拽改变
    rowResize: Boolean,
    buttonList: Array as any,
    topButtonList: Array as any,
    height: Number,
  });
  const [registerModal, { openModal }] = useModal();
  const data = ref<Recordable[]>([]);
  //缓存字段是否disable
  const cacheMap = new Map<String, number[]>();
  const isCamelCase = inject<boolean>('isCamelCase', false);
  const madomkey = ref<string>(Math.random().toString(36).slice(-8));
  const columns = ref<SubFormColumn[]>(props.columns);
  // 注入表单数据
  const formModel = inject<any>('formModel', null);
  const curRecord = ref();
  const curButtonModalConfig = ref();
  const { notification } = useMessage();
  onMounted(() => {
    data.value = cloneDeep(props.value);

    if (props.showIndex && columns.value && columns.value[0].key !== 'index') {
      columns.value.unshift({
        title: '序号',
        key: 'index',
        align: 'center',
        width: 60,
      });
    }
    columns.value = filterColum(columns.value);
  });

  watch(
    () => data.value,
    async (val) => {
      if (val?.length) {
        val.forEach((item, index) => {
          item.key = index;
        });
      }
      setTimeout(() => {
        if (val.length) {
          if (props.rowSpan) {
            let colName: string = !isCamelCase
              ? props.rowSpan
              : camelCaseString(props.rowSpan) || '';
            let curI = 0;
            let cur = val[curI][colName];
            let arr: number[] = [];
            val.forEach((o, i) => {
              arr.push(1);
              if (i >= 1) {
                if (
                  o[colName] == cur &&
                  o[colName] !== '' &&
                  o[colName] !== null &&
                  o[colName] !== undefined
                ) {
                  arr[curI] += 1;
                  arr[i] = 0;
                } else {
                  curI = i;
                  cur = val[curI][colName];
                }
              }
            });

            columns.value.forEach((item) => {
              if (item.dataIndex == colName) {
                item.customCell = (_, index) => {
                  let obj = { rowSpan: 1 };
                  arr.forEach((o, i) => {
                    if (index == i) {
                      obj = { rowSpan: o };
                    }
                  });
                  return obj;
                };
              }
            });
          }
        }
      }, 200);

      emit('change', val);
      emit('update:value', val);
      handleResizeRow();
    },
    {
      deep: true,
    },
  );

  watch(
    () => props.columns,
    (val) => {
      columns.value = filterColum(val);
    },
  );

  watch(
    () => props.value,
    (v) => {
      data.value = v;

      //要保证在预加载之后在emit  不然预加载数据不会绑定到表单数据中
      emit('change', unref(data));
      emit('update:value', unref(data));
      emit('load', unref(data));
    },
    { deep: true },
  );
  const selectedRowsData = ref<any>([]);
  const rowSelection: TableProps['rowSelection'] = {
    onChange: (selectedRowKeys: string[], selectedRows) => {
      selectedRowsData.value = selectedRows;
      emit('select', { selectedRowKeys, selectedRows });
    },
  };
  function handleResizeRow() {
    if (!props.rowResize) return;
    nextTick(() => {
      const table = document.getElementById('table' + madomkey.value);
      const rows: any = table?.querySelectorAll('.ant-table-row');
      for (let row of rows) {
        const resizable: any = row.getElementsByClassName('ant-table-cell');
        for (let item of resizable) {
          const handle = item.querySelector('.resize-handle');
          let originY, originHeight;

          handle?.addEventListener('mousedown', function (e) {
            originY = e.clientY;
            originHeight = item.offsetHeight;

            document.addEventListener('mousemove', resize);
            document.addEventListener('mouseup', stopResize);
          });

          function resize(e) {
            const height = originHeight + (e.clientY - originY);
            resizable[0].style.height = `${height}px`;
          }

          function stopResize() {
            document.removeEventListener('mousemove', resize);
            document.removeEventListener('mouseup', stopResize);
          }
        }
      }
    });
  }
  const add = () => {
    //给各个组件赋默认值
    const pushObj: Recordable = {};

    //新增数据钩子
    if (isFunction(props.addBefore)) {
      props.addBefore(formModel, pushObj);
    }

    props.columns.forEach((column, index) => {
      //判断是否为操作菜单  并且设置了默认值
      if (column.key === 'index' && index === 0) return;
      if (column.key !== 'action') {
        if (column.componentType === 'RangePicker' || column.componentType === 'TimeRangePicker') {
          handleSetRangeTimeValue(pushObj, column.dataIndex as string);
        } else if (
          (column.componentType &&
            staticDataComponents.includes(column.componentType) &&
            (column.componentProps as any)?.datasourceType === 'staticData') ||
          (column.componentType &&
            DicDataComponents.includes(column.componentType) &&
            (column.componentProps as any)?.datasourceType === 'dic')
        ) {
          let { defaultSelect } = column.componentProps as any;
          pushObj[column!.dataIndex as string] = defaultSelect;
        } else {
          pushObj[column!.dataIndex as string] = column.defaultValue;
        }
      }
    });
    data.value.push(pushObj);
    emit('change', unref(data));
    emit('update:value', unref(data));
    //新增数据钩子
    if (isFunction(props.addAfter)) {
      props.addAfter(formModel, pushObj);
    }
    emit('add', unref(data));
  };

  const remove = (index) => {
    data.value.splice(index, 1);
    emit('change', unref(data));
    emit('update:value', unref(data));
    emit('delete', unref(data));
  };
  /**
   * @author: tzx
   * @description: 设置RangeTime的值
   *
   */
  function handleSetRangeTimeValue(values: Recordable, field: string) {
    const startTimeKey = field.split(',')[0];
    const endTimeKey = field.split(',')[1];
    values[startTimeKey] = '';
    values[endTimeKey] = '';

    return values;
  }
  const rules = (column, record, index) => {
    if (column.key === 'index') return;
    const requiredRule = {
      required: getComponentsProps(column, record, index)?.required || false,
      message: `${column.title}是必填项`,
    };
    const rulesList = cloneDeep(getComponentsProps(column, record, index)?.rules);
    if (!rulesList) return [requiredRule];
    rulesList?.map((item) => (item.pattern = eval(item.pattern)));
    return [...rulesList, requiredRule];
  };
  function handleResizeColumn(w, col) {
    col.width = w;
  }
  const getComponentsProps = (column, record, index) => {
    let componentProps = cloneDeep(column?.componentProps);
    const dataIndex = column?.dataIndex;
    if (!componentProps) return;
    if (isFunction(componentProps)) {
      componentProps = componentProps({ updateSchema, formModel, record, index, disableRow }) ?? {};
    } else {
      if (componentProps['events']) {
        for (const eventKey in componentProps['events']) {
          try {
            const event = new Function(
              'schema',
              'formModel',
              'formActionType',
              'eventData',
              `${componentProps['events'][eventKey]}`,
            );

            componentProps['on' + upperFirst(eventKey)] = function (e) {
              event(column, formModel, props.formApi, e);
            };
          } catch (error) {
            notification.error({
              message: 'Tip',
              description: '触发事件填写有误！',
            });
          }
        }
      }
    }
    if (isBoolean(props.disabled)) {
      componentProps['disabled'] = componentProps['disabled'] || props.disabled;
    } else if (isBoolean(componentProps['disabled'])) {
      componentProps['disabled'] =
        cacheMap.has(dataIndex) && cacheMap.get(dataIndex)?.includes(index) ? true : false;
    }

    return componentProps as Recordable;
  };

  const disableRow = (column: SubFormColumn, index?: number) => {
    let col: any = columns.value.find((x) => x.dataIndex == column.dataIndex);
    if (col && index !== undefined) {
      //如果当前字段已经缓存
      if (cacheMap.has(col.dataIndex)) {
        let indexArray = cacheMap.get(col.dataIndex);

        if (column.componentProps.disabled) {
          if (!indexArray) {
            indexArray = [index];
          } else {
            if (!indexArray.includes(index)) {
              indexArray.push(index);
            }
          }
        } else {
          if (indexArray) {
            if (indexArray.findIndex((x) => x === index) > -1) {
              indexArray.splice(
                indexArray.findIndex((x) => x === index),
                1,
              );
            }
          }
        }
      } else {
        if (column.componentProps.disabled) {
          cacheMap.set(col.dataIndex, [index]);
        }
      }
    }
  };

  const updateSchema = (column: SubFormColumn, index?: number) => {
    let col: any = columns.value.find((x) => x.dataIndex == column.dataIndex);
    if (col && index !== undefined) {
      //如果当前字段已经缓存
      if (cacheMap.has(col.dataIndex)) {
        let indexArray = cacheMap.get(col.dataIndex);

        if (column.componentProps.disabled) {
          if (!indexArray) {
            indexArray = [index];
          } else {
            indexArray.push(index);
          }
        } else {
          if (indexArray) {
            if (indexArray.findIndex((x) => x === index) > -1) {
              indexArray.splice(
                indexArray.findIndex((x) => x === index),
                1,
              );
            }
          }
        }
      } else {
        if (column.componentProps.disabled) {
          cacheMap.set(col.dataIndex, [index]);
        }
      }
    }
    return col || col?.length ? deepMerge(col, column) : col;
  };
  function isAlphaString1(str) {
    return /^[a-zA-Z]+$/.test(str) ? 10 : 15;
  }
  function filterColum(column) {
    if (props.widths) {
      props.widths.forEach((o: any) => {
        let obj: any = column.find((k) => k.key == o.key);
        if (obj) {
          let width = o.resizable ? o.width : o.unit && o.width ? o.width + o.unit : o.width;
          if (width === 0 || width) obj.width = width;
          if (o.minWidth === 0 || o.minWidth) obj.minWidth = o.minWidth;
          if (o.maxWidth === 0 || o.maxWidth) obj.maxWidth = o.maxWidth;
          obj.resizable = o.resizable;
          obj.isEdit = o.isEdit;
          if (o.isEdit) obj.ellipsis = true;
        }
      });
    }
    if (props.buttonList?.length > 0) {
      let w = 30;
      props.buttonList.forEach((o) => {
        if (o.icon) {
          w += 26;
        } else if (o.label) {
          w += String(o.label).length * isAlphaString1(o.label);
        }
      });
      let obj = column.find((k) => k.key == 'action');
      if (obj) obj.width = w + 'px';
    }
    return column?.filter((o) => {
      return (
        o.key == 'action' ||
        o.key == 'index' ||
        (((isBoolean(o.show) && o.show) || !isBoolean(o.show)) &&
          isBoolean(o.componentProps?.isShow) &&
          o.componentProps?.isShow) ||
        !isBoolean(o.componentProps?.isShow)
      );
    });
  }
  function showModal(column, record, index) {
    curRecord.value = index;
    curButtonModalConfig.value = { ...column.componentProps, title: column.title };
    if (column.componentProps.events && column.componentProps.events.click) {
      if (!column.componentProps.events.click.includes('formActionType.openModal')) {
        customOpenModal(record);
      }
      let obj = {
        selectedRows: selectedRowsData.value,
        tableDatas: data.value,
        curRow: record,
        curIndex: index,
        formApi,
      };
      executeCurFormEvent(
        [
          {
            operateType: ExecuteType.JS,
            operateConfig: { js: column.componentProps.events.click },
          },
        ],
        formModel,
        isCamelCase,
        obj,
      );
    } else {
      customOpenModal(record);
    }
  }
  function customClick(executeButton, record?, index?) {
    curRecord.value = index;
    curButtonModalConfig.value = executeButton.modal;
    let obj = {
      selectedRows: selectedRowsData.value,
      tableDatas: data.value,
      curRow: record,
      curIndex: index,
      curParentIndex: props.subFormIndex,
      formApi,
    };
    executeCurFormEvent(executeButton.event, formModel, isCamelCase, obj);
  }
  const customOpenModal = (record) => {
    if (record && curButtonModalConfig.value?.bindModal) {
      openModal(true, { isUpdate: true, record, modal: curButtonModalConfig.value });
    }
  };
  const formApi = { openModal: customOpenModal };
</script>
<style lang="less" scoped>
  :deep(.ant-form-item) {
    margin-bottom: 0;
  }

  :deep(.ant-table-cell) {
    padding: 8px 0;
  }

  :deep(.ant-table .ant-table-thead tr th) {
    padding: 11px;
  }

  :deep(.ant-input-number),
  :deep(.ant-input-affix-wrapper),
  :deep(.ant-input),
  :deep(.ant-select-selector),
  :deep(.ant-picker) {
    border: 0;
    box-shadow: none !important;
  }

  :deep(.anticon) {
    padding-bottom: 0 !important;
  }

  :deep(.ant-table-cell-fix-right) {
    text-align: center;
    width: 60px;
  }

  :deep(.ant-radio-group),
  :deep(.ant-checkbox-group),
  :deep(.ant-rate),
  :deep(.ant-upload),
  :deep(.ant-form-item-explain-error) {
    padding: 0 11px;
  }

  :deep(.ant-switch),
  :deep(input[type='color']) {
    margin: 0 11px;
  }

  .select-btn {
    margin-bottom: 8px;

    :deep(.ant-upload) {
      padding: 0;
    }
  }

  .resize-handle {
    width: 100%;
    height: 1px;
    right: 0;
    bottom: 0;
    cursor: row-resize;
    border-top: 1px solid #1c8dff;
    position: absolute;
    opacity: 0;
  }

  tr:hover {
    .resize-handle {
      opacity: 1;
    }
  }
</style>
