<template>
  <div class="layout-box">
    <div class="resize-layout">
      <div class="resize-left" ref="left"
        ><!-- 中间区域 -->
        <div
          class="content-box"
          ref="contentBox"
          v-if="data.list.length > 0"
          :style="{
            backgroundImage: `url(${imageUrl})`,
            backgroundRepeat: data.background.repeat,
            backgroundSize: data.background.size,
          }"
        >
          <grid-layout
            v-model:layout="data.list"
            :col-num="12"
            :row-height="30"
            :is-draggable="true"
            :is-resizable="true"
            :is-mirrored="false"
            :vertical-compact="true"
            :margin="[10, 10]"
            :use-css-transforms="false"
          >
            <grid-item
              v-for="(item, index) in data.list"
              :x="item.x"
              :y="item.y"
              :w="item.w"
              :h="item.h"
              :i="item.i"
              :key="item.i"
              :maxH="item.maxH"
              :minH="item.minH"
              :maxW="item.maxW"
              :minW="item.minW"
              :class="{ 'active-item': item.i === currentId && !data.isGenerateThumb }"
              :style="{
                maxWidth: item.type == 'Banner' ? 'calc(100% - 20px)' : '100%',
              }"
              @click="changeSelect(index)"
            >
              <component
                :id="item.i"
                :w="item.w"
                :h="item.h"
                :type="item.type"
                v-model:config="item.config"
                :title="item.config.title"
                :class="[
                  'item-box',
                  (item.type == DesktopComponent.TITLE && item.config.isBlock) ||
                  item.type !== DesktopComponent.TITLE
                    ? 'shadow'
                    : '',
                ]"
                :is="getLegendComponent(item.type)"
                :key="data.renderKey"
              />
              <div class="mask">
                <div class="button-list" v-if="item.i === currentId && !data.isGenerateThumb">
                  <a-button shape="circle" size="small" class="clone-button">
                    <Icon
                      icon="ant-design:copy-outlined"
                      class="action-clone"
                      @click.stop="copyComponent(index)"
                    />
                  </a-button>
                  <a-button shape="circle" size="small" danger class="delete-button">
                    <Icon
                      icon="ant-design:delete-outlined"
                      class="action-delete"
                      @click.stop="removeComponent(index)"
                    />
                  </a-button>
                </div>
              </div>
            </grid-item>
          </grid-layout>
        </div>
        <div
          v-if="data.list.length == 0"
          class="empty-box"
          :style="{
            backgroundImage: `url(${imageUrl})`,
            backgroundRepeat: data.background.repeat,
            backgroundSize: data.background.size,
          }"
        >
          <img :src="DesktopEmpty" />
        </div>
      </div>
      <div class="resize-line-box" v-if="showPanel"></div>
      <div class="resize-right" ref="right">
        <div class="fewer-panel-box">
          <NodeHead :nodeName="propertiesTitle" class="fewer-panel-title" />
          <div class="right-box" v-if="data.background.isShow">
            <component
              :is="getComponentProperties(DesktopComponent.BACKGROUND)"
              :info="data.background"
            />
          </div>
          <div class="right-box" v-else-if="data.list.length > 0">
            <!-- 属性 -->
            <template v-for="(item, index) in data.list" :key="index">
              <component
                v-show="data.currentComponentIndex == index"
                :is="getComponentProperties(item.type)"
                :allTableList="allTableList"
                :info="item"
              />
            </template>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
  import { computed, nextTick, onMounted, onUnmounted, provide, reactive, ref, watch } from 'vue';
  import html2canvas from 'html2canvas';
  import { Icon } from '/@/components/Icon';
  import { BackgroundSetting, DesktopInfoItem } from '/@/model/desktop/designer';
  import { DesktopComponent } from '/@/enums/desktop';
  import { cloneDeep } from 'lodash-es';
  import { backgroundInfo, defaultInfo, InfoByType } from './config/info';
  import { componentTitleFromType } from './config/components';
  import { dataURLtoBlob } from '/@/utils/file/base64Conver';
  import { uploadBlobApi } from '/@/api/sys/upload';
  import useComponentByType from '../../hooks/useComponentByType';
  import { debounce } from 'lodash-es';
  import { NodeHead } from '/@/components/ModalPanel/index';
  import DesktopEmpty from '/@/assets/desktop/desktop-empty.png';
  import { getFileList } from '/@/api/system/file';
  import { getFileUrl } from '/@/utils/event/design';

  let left = ref();
  let right = ref();
  let contentBox = ref();
  let showPanel = ref(false);
  const props = withDefaults(
    defineProps<{
      list: Array<DesktopInfoItem>;
      background: BackgroundSetting;
    }>(),
    {
      list: () => {
        return [];
      },
      background: () => {
        return backgroundInfo;
      },
    },
  );

  const { componentByType } = useComponentByType();
  const data: {
    currentComponentIndex: number;
    renderKey: number;
    list: Array<DesktopInfoItem>;
    showPreview: boolean;
    isGenerateThumb: boolean;
    background: BackgroundSetting;
  } = reactive({
    currentComponentIndex: -1,
    list: [],
    renderKey: 0,
    showPreview: false,
    isGenerateThumb: false,
    background: backgroundInfo,
  });
  const imageUrl = ref('');

  watch(
    () => data.background.image,
    () => {
      getImage();
    },
  );
  const currentId = computed(() => {
    return data.list.length > 0 ? data.list[data.currentComponentIndex].i : 0;
  });
  const currentInfo = computed(() => {
    return data.background.isShow
      ? data.background
      : data.list.length > 0
      ? data.list[data.currentComponentIndex]
      : null;
  });
  const propertiesTitle = computed(() => {
    return showPanel.value && currentInfo.value
      ? componentTitleFromType.get(currentInfo.value.type)
      : '';
  });
  const allTableList = computed(() => {
    let dataList: Array<any> = [];
    let temp = cloneDeep(data.list).filter((ele) => {
      return ele.type == DesktopComponent.TABLE;
    });
    if (temp.length > 0) {
      temp.forEach((element) => {
        let obj = {
          title: element.config.title,
          value: element.i,
          disabled: false,
        };
        dataList.push(obj);
      });
    }
    return dataList;
  });
  provide('getTableList', getTableList);
  onMounted(() => {
    initDisplay();
    window.addEventListener('resize', () => {
      debounceResetDisplay();
    });
  });
  onUnmounted(() => {
    debounceResetDisplay.cancel();
    window.removeEventListener('resize', () => {
      debounceResetDisplay();
    });
  });
  const debounceResetDisplay = debounce(resetDisplay, 500, {
    leading: true, // 延长开始后调用
    trailing: false, // 延长结束前调用
  });
  function getTableList() {
    return cloneDeep(data.list);
  }
  function initDisplay() {
    data.list = [];
    if (props.background.image || props.background.repeat || props.background.size) {
      data.background = props.background;
    }
    if (props.list && props.list.length > 0) {
      data.list = props.list;
      data.currentComponentIndex = 0;
      // showPropertiesBox();
    }
  }
  function getNewY() {
    let newY = 0;
    let height = 0;
    if (data.list.length > 0) {
      let arrFromX = data.list.filter((ele) => {
        return ele.x === 0;
      });
      if (arrFromX.length > 0) {
        arrFromX.forEach((element) => {
          if (element.y >= newY) {
            newY = element.y;
            height = element.h;
          }
        });
        newY = newY + height;
      }
    }

    return newY;
  }
  function addComponent(type: DesktopComponent) {
    let info: DesktopInfoItem | undefined = defaultInfo;
    if (InfoByType.has(type)) {
      info = InfoByType.get(type);
    }
    if (info) {
      info.x = 0;
      info.y = 0;
      if (data.list.length > 0) {
        info.y = getNewY();
      }
      info.i = Date.now() + '_' + Math.ceil(Math.random() * 99999);
      data.list.push(cloneDeep(info));
      data.currentComponentIndex = data.list.length - 1;
      data.background.isShow = false;
      showPropertiesBox();
    }
  }
  function copyComponent(index: number) {
    let info: DesktopInfoItem = cloneDeep(data.list[index]);
    info.x = 0;
    info.y = getNewY();
    info.i = Date.now() + '_' + Math.ceil(Math.random() * 99999);
    data.list.push(info);
    data.currentComponentIndex = data.list.length - 1;
    data.background.isShow = false;
    showPropertiesBox();
  }
  function showPropertiesBox() {
    if (!showPanel.value) {
      setTimeout(() => {
        showPanel.value = true;
        showRightBox();
      }, 1);
    }
  }
  function removeComponent(index: number) {
    data.currentComponentIndex = 0;
    data.list.splice(index, 1);
    data.background.isShow = false;
    hidePropertiesBox();
  }
  function hidePropertiesBox() {
    if (showPanel.value) {
      setTimeout(() => {
        showPanel.value = false;
        hideRightBox();
      }, 1);
    }
  }
  function setBackground() {
    data.background.isShow = true;
    showPropertiesBox();
  }
  function changeSelect(index: number) {
    data.currentComponentIndex = index;
    data.background.isShow = false;
    showPropertiesBox();
  }
  function resetDisplay() {
    data.renderKey++;
  }
  function getLegendComponent(type: DesktopComponent) {
    return componentByType.has(type)
      ? componentByType.get(type)?.legend
      : componentByType.get(DesktopComponent.DEFAULT)?.legend;
  }
  // function getPropertiesTitle(type) {
  //   return showPanel.value ? componentTitleFromType.get(type) : null;
  // }
  function getComponentProperties(type) {
    return componentByType.has(type)
      ? componentByType.get(type)?.properties
      : componentByType.get(DesktopComponent.DEFAULT)?.properties;
  }
  function showRightBox() {
    showPanel.value = true;
    left.value.style.width = 'calc(100% - 470px)';
    right.value.style.width = '460px';
    resetDisplay();
  }
  function hideRightBox() {
    showPanel.value = false;
    left.value.style.width = '99%';
    right.value.style.width = '0';
    resetDisplay();
  }
  function getDesignData() {
    return data.list;
  }
  async function saveDesignData(isGetUrl = true) {
    if (isGetUrl) {
      data.isGenerateThumb = true;
      await nextTick();
      let thumb = await generateThumb();
      let backgroundUrl = await uploadSign(thumb);
      return { list: data.list, backgroundUrl, background: data.background };
    } else {
      return { list: data.list, background: data.background };
    }
  }
  async function uploadSign(base64) {
    try {
      const blob = dataURLtoBlob(base64);
      const fileUrl = await uploadBlobApi(blob, 'thumb.png');
      return fileUrl;
    } catch (error) {
      return '';
    }
  }
  async function generateThumb() {
    try {
      let canvas = await html2canvas(contentBox.value, {
        backgroundColor: '#f5f5f5',
        useCORS: true,
      });
      return canvas.toDataURL();
    } catch (error) {
      return '';
    }
  }
  async function getImage() {
    if (data.background.image) {
      let fileList = await getFileList({ folderId: data.background.image });
      if (fileList.length) {
        imageUrl.value = getFileUrl(fileList[0]);
      }
    } else {
      imageUrl.value = '';
    }
  }
  defineExpose({
    saveDesignData,
    getDesignData,
    addComponent,
    setBackground,
  });
</script>

<style lang="less" scoped>
  .box {
    position: relative;
    width: 100%;
    height: 100%;
  }

  .div-column {
    position: absolute;
    left: 0;
    width: 68px;
    height: 100%;
    display: flex;
  }

  .resize-layout {
    display: flex;
    height: 100%;
    width: 100%;
  }

  .resize-left {
    width: 100%;
    padding: 0;
    overflow: hidden;
  }

  .resize-shrink-sidebar {
    cursor: col-resize;
    display: flex;
    justify-content: center;
    align-items: center;
  }

  .shrink-sidebar-text {
    border-radius: 4px;

    /* color: #fff; */
  }

  .shrink-sidebar:hover {
    color: #666;
  }

  .resize-line-box {
    flex-basis: 10px;
  }

  .resize-right {
    width: 0;

    /* 右侧初始化宽度 */
  }

  .fewer-panel-box {
    height: 100%;
    background-color: #fff;
    border-radius: 16px;
  }

  .right-box {
    height: 100%;

    :deep(.add-custom) {
      color: @primary-color;
      font-size: 14px;
      position: absolute;
      top: 14px;
      right: 33px;
    }
  }

  .fewer-panel-title {
    padding-left: 10px;
    margin-top: 1px;
    height: 50px;
    border-bottom: 1px solid#EEEEEE;
    display: flex;
    align-items: center;
  }

  .vue-grid-layout {
    height: 100%;
  }

  .content-box {
    height: 100%;
    overflow: auto;
    background-color: #fff;
    border-radius: 16px;
  }

  .button-list {
    position: absolute;
    right: 0;
    top: -10px;
  }

  .action-clone {
    color: @primary-color;
  }

  .clone-button {
    background-color: #eff4ff;
    margin-right: 4px;
  }

  .delete-button {
    background-color: #fce3e8;
    margin-right: 4px;
  }

  .action-delete {
    color: @clear-color;
  }

  .mask {
    position: absolute;
    inset: 0;
    padding: 2px;
  }

  .active-item {
    border: 1px solid #39f;
  }

  .item-box {
    position: relative;
    width: 100%;
    height: 100%;
    min-width: 10px;
    min-height: 10px;
  }

  .shadow {
    box-shadow: 0 3px 6px 1px rgb(0 0 0 / 16%);
    border-radius: 4px;
    background-color: #fff;
  }

  .vue-grid-item:hover {
    border: 1px dotted #39f;
  }

  .empty-box {
    width: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    height: calc(100% - 90px);
    overflow: auto;
    padding-bottom: 60px;
    border-radius: 16px;

    img {
      width: 480px;
    }
  }

  :deep(.ant-collapse-header) {
    font-weight: bold;
  }
</style>
