<template>
  <div
    ref="courserware"
    class="courserware"
    :style="[
      {
        backgroundImage: background.background_image_url ? `url(${background.background_image_url})` : '',
        backgroundSize: background.background_image_url
          ? `${background.background_position.width}% ${background.background_position.height}%`
          : '',
        backgroundPosition: background.background_image_url
          ? `${background.background_position.left}% ${background.background_position.top}%`
          : '',
      },
    ]"
  >
    <template v-for="(row, i) in data.row_list">
      <div v-show="computedRowVisibility(row.row_id)" :key="i" class="row" :style="getMultipleColStyle(i)">
        <el-checkbox
          v-if="
            isShowGroup &&
            groupRowList.find(({ row_id, is_pre_same_group }) => row.row_id === row_id && !is_pre_same_group)
          "
          v-model="rowCheckList[row.row_id]"
          :class="['row-checkbox', `${row.row_id}`]"
        />
        <!-- 列 -->
        <template v-for="(col, j) in row.col_list">
          <div :key="j" :class="['col', `col-${i}-${j}`]" :style="computedColStyle(col)">
            <!-- 网格 -->
            <template v-for="(grid, k) in col.grid_list">
              <component
                :is="previewComponentList[grid.type]"
                :id="grid.id"
                :key="k"
                ref="preview"
                :content="computedColContent(grid.id)"
                :class="[grid.id]"
                :data-id="grid.id"
                :style="{
                  gridArea: grid.grid_area,
                  height: grid.height,
                }"
                @contextmenu.native.prevent="handleContextMenu($event, grid.id)"
              />

              <div
                v-if="showMenu && componentId === grid.id"
                :key="'menu' + grid.id + k"
                class="custom-context-menu"
                :style="{ left: menuPosition.x + 'px', top: menuPosition.y + 'px' }"
                @click="handleMenuItemClick"
              >
                添加批注
              </div>
              <div
                v-if="showRemark && Object.keys(componentRemarkObj).length !== 0 && componentRemarkObj[grid.id]"
                :key="'show' + grid.id + k"
              >
                <el-popover
                  v-for="(items, indexs) in componentRemarkObj[grid.id]"
                  :key="indexs"
                  placement="bottom"
                  width="200"
                  trigger="click"
                >
                  <div v-html="items.content"></div>
                  <template #reference>
                    <SvgIcon
                      slot="reference"
                      icon-class="icon-info"
                      size="24"
                      class="remark-info"
                      :style="{ left: items.position_x - 12 + 'px', top: items.position_y - 12 + 'px' }"
                    />
                  </template>
                </el-popover>
              </div>
            </template>
          </div>
        </template>
      </div>
    </template>
  </div>
</template>

<script>
import { previewComponentList } from '@/views/book/courseware/data/bookType';

export default {
  name: 'CoursewarePreview',
  provide() {
    return {
      getDragStatus: () => false,
      bookInfo: this.bookInfo,
    };
  },
  props: {
    data: {
      type: Object,
      default: () => ({}),
    },
    background: {
      type: Object,
      default: () => ({}),
    },
    componentList: {
      type: Array,
      required: true,
    },
    canRemark: {
      type: Boolean,
      default: false,
    },
    showRemark: {
      type: Boolean,
      default: false,
    },
    componentRemarkObj: {
      type: Object,
      default: () => ({}),
    },
    groupRowList: {
      type: Array,
      default: () => [],
    },
    isShowGroup: {
      type: Boolean,
      default: false,
    },
    groupShowAll: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      previewComponentList,
      bookInfo: {
        theme_color: '',
      },
      showMenu: false,
      divPosition: {
        left: 0,
        top: 0,
      }, // courserware盒子原始距离页面顶部和左边的距离
      menuPosition: { x: 0, y: 0, select_node: '' }, // 用于存储菜单的位置
      componentId: '', // 添加批注的组件id
      rowCheckList: {},
    };
  },
  watch: {
    groupRowList: {
      handler(val) {
        if (!val) return;
        this.rowCheckList = val
          .filter(({ is_pre_same_group }) => !is_pre_same_group)
          .reduce((acc, row) => {
            acc[row.row_id] = false;
            return acc;
          }, {});
      },
    },
  },
  mounted() {
    const element = this.$refs.courserware;
    const rect = element.getBoundingClientRect();
    this.divPosition = {
      left: rect.left,
      top: rect.top,
    };
    window.addEventListener('mousedown', this.handleMouseDown);
  },
  beforeDestroy() {
    window.removeEventListener('mousedown', this.handleMouseDown);
  },
  methods: {
    /**
     * 计算组件内容
     * @param {string} id 组件id
     * @returns {string} 组件内容
     */
    computedColContent(id) {
      if (!id) return '';
      return this.componentList.find((item) => item.component_id === id)?.content || '';
    },
    getMultipleColStyle(i) {
      let row = this.data.row_list[i];
      let col = row.col_list;
      if (col.length <= 1) {
        return {
          gridTemplateColumns: '100fr',
        };
      }
      let gridTemplateColumns = row.width_list.join(' ');

      return {
        gridAutoFlow: 'column',
        gridTemplateColumns,
        gridTemplateRows: 'auto',
      };
    },
    /**
     * 计算行的可见性
     * @params {string} rowId 行的ID
     */
    computedRowVisibility(rowId) {
      if (this.groupShowAll) return true;
      let { row_id, is_pre_same_group } = this.groupRowList.find(({ row_id }) => row_id === rowId);
      if (is_pre_same_group) {
        const index = this.groupRowList.findIndex(({ row_id }) => row_id === rowId);
        if (index === -1) return false;
        for (let i = index - 1; i >= 0; i--) {
          if (!this.groupRowList[i].is_pre_same_group) {
            return this.rowCheckList[this.groupRowList[i].row_id];
          }
        }
        return false;
      }
      return this.rowCheckList[row_id];
    },
    /**
     * 分割整数为多个 1的倍数
     * @param {number} num
     * @param {number} parts
     */
    splitInteger(num, parts) {
      let base = Math.floor(num / parts);
      let arr = Array(parts).fill(base);
      let remainder = num - base * parts;
      for (let i = 0; remainder > 0; i = (i + 1) % parts) {
        arr[i] += 1;
        remainder -= 1;
      }
      return arr;
    },
    computedColStyle(col) {
      const grid = col.grid_list;

      let maxCol = 0; // 最大列数
      let rowList = new Map();
      grid.forEach(({ row }) => {
        rowList.set(row, (rowList.get(row) || 0) + 1);
      });
      let curMaxRow = 0; // 当前数量最大 row 的值
      rowList.forEach((value, key) => {
        if (value > maxCol) {
          maxCol = value;
          curMaxRow = key;
        }
      });
      // 计算 grid_template_areas
      let gridTemplateAreas = '';
      let gridArr = [];
      grid.forEach(({ grid_area, row }) => {
        if (!gridArr[row - 1]) {
          gridArr[row - 1] = [];
        }
        if (curMaxRow === row) {
          gridArr[row - 1].push(`${grid_area}`);
        } else {
          let filter = grid.filter((item) => item.row === row);
          let find = filter.findIndex((item) => item.grid_area === grid_area);
          let needNum = maxCol - filter.length; // 需要的数量

          let str = '';
          if (filter.length === 1) {
            str = ` ${grid_area} `.repeat(needNum + 1);
          } else {
            let arr = this.splitInteger(needNum, filter.length);
            str = arr[find] === 0 ? ` ${grid_area} ` : ` ${grid_area} `.repeat(arr[find] + 1);
          }
          gridArr[row - 1].push(`${str}`);
        }
      });
      gridArr.forEach((item) => {
        gridTemplateAreas += `'${item.join(' ')}' `;
      });

      // 计算 grid_template_columns
      let gridTemplateColumns = '';
      let max = { row: 0, num: 0 };
      grid.forEach(({ row }) => {
        // 计算出 row 的哪个值最多
        let len = grid.filter((item) => item.row === row).length;
        if (max.num < len) {
          max.num = len;
          max.row = row;
        }
      });
      grid.forEach((item) => {
        if (item.row === max.row) {
          gridTemplateColumns += `${item.width} `;
        }
      });

      // 计算 grid_template_rows
      let gridTemplateRows = '';
      // 将 grid 按照 row 分组
      let gridMap = new Map();
      grid.forEach((item) => {
        if (!gridMap.has(item.row)) {
          gridMap.set(item.row, []);
        }
        gridMap.get(item.row).push(item.height);
      });
      gridMap.forEach((value) => {
        if (value.length === 1) {
          gridTemplateRows += `${value[0]} `;
        } else {
          let isAllAuto = value.every((item) => item === 'auto'); // 是否全是 auto
          gridTemplateRows += isAllAuto ? 'auto ' : `max(${value.join(', ')}) `;
        }
      });

      return {
        width: col.width,
        gridTemplateAreas,
        gridTemplateColumns,
        gridTemplateRows,
      };
    },
    handleContextMenu(event, id) {
      if (this.canRemark) {
        event.preventDefault(); // 阻止默认的上下文菜单显示
        this.menuPosition = {
          x: event.clientX - this.divPosition.left,
          y: event.clientY - this.divPosition.top,
        }; // 设置菜单位置
        this.componentId = id;
        this.$emit('computeScroll');
      }
    },
    handleResult(top, left, select_node) {
      this.menuPosition = {
        x: this.menuPosition.x + left,
        y: this.menuPosition.y + top,
        select_node,
      }; // 设置菜单位置
      this.showMenu = true; // 显示菜单
    },
    handleMenuItemClick() {
      this.showMenu = false; // 隐藏菜单
      this.$emit(
        'addRemark',
        this.menuPosition.select_node,
        this.menuPosition.x,
        this.menuPosition.y,
        this.componentId,
      );
    },
    handleMouseDown(event) {
      if (event.button === 0 && event.target.className !== 'custom-context-menu') {
        // 0 表示左键
        this.showMenu = false;
      }
    },
    /**
     * 查找子组件
     * @param {string} id 组件的唯一标识符
     * @returns {Promise<HTMLElement|null>} 返回找到的子组件或 null
     */
    async findChildComponentByKey(id) {
      await this.$nextTick();
      return this.$refs.preview.find((child) => child.$el && child.$el.dataset && child.$el.dataset.id === id);
    },
    /**
     * 模拟回答
     * @param {boolean} isJudgingRightWrong 是否判断对错
     * @param {boolean} isShowRightAnswer 是否显示正确答案
     * @param {boolean} disabled 是否禁用
     */
    simulateAnswer(isJudgingRightWrong, isShowRightAnswer, disabled = true) {
      this.$refs.preview.forEach((item) => {
        item.showAnswer(isJudgingRightWrong, isShowRightAnswer, null, disabled);
      });
    },
  },
};
</script>

<style lang="scss" scoped>
.courserware {
  position: relative;
  display: flex;
  flex-direction: column;
  row-gap: $component-spacing;
  width: 100%;
  height: 100%;
  min-height: calc(100vh - 226px);
  padding-top: $courseware-top-padding;
  padding-bottom: $courseware-bottom-padding;
  margin: 15px 0;
  background-color: #fff;
  background-repeat: no-repeat;
  border-bottom-right-radius: 12px;
  border-bottom-left-radius: 12px;

  &::before,
  &::after {
    position: absolute;
    left: 0;
    width: 100%;
    height: 15px;
    pointer-events: none;
    content: '';
    background: #f9f9f9;
  }

  &::before {
    top: -15px;
  }

  &::after {
    bottom: -15px;
  }

  .row {
    display: grid;
    gap: $component-spacing;

    .col {
      display: grid;
      gap: $component-spacing;
      overflow: hidden;
    }

    .row-checkbox {
      position: absolute;
      left: 4px;
    }
  }

  .custom-context-menu,
  .remark-info {
    position: absolute;
    z-index: 999;
    display: flex;
    gap: 3px;
    align-items: center;
    font-size: 14px;
    cursor: pointer;
  }

  .custom-context-menu {
    padding-left: 30px;
    background: url('../../../../assets/icon-publish.png') left center no-repeat;
    background-size: 24px;
  }
}
</style>
