<template>
  <div 
    class="thumbnails"
    @mousedown="() => setThumbnailsFocus(true)"
    v-click-outside="() => setThumbnailsFocus(false)"
    v-contextmenu="contextmenusThumbnails"
  >
    <div class="add-slide">
      <div class="btn" @click="createSlide()"><IconPlus class="icon" />添加幻灯片</div>
      <Popover trigger="click" placement="bottomLeft" v-model:visible="presetLayoutPopoverVisible">
        <template #content>
          <LayoutPool @select="slide => { createSlideByTemplate(slide); presetLayoutPopoverVisible = false }" />
        </template>
        <div class="select-btn"><IconDown /></div>
      </Popover>
    </div>

    <Draggable 
      class="thumbnail-list"
      :modelValue="slides"
      :animation="300"
      :scroll="true"
      :scrollSensitivity="50"
      :setData="null"
      @end="handleDragEnd"
      itemKey="id"
    >
      <template #item="{ element, index }">
        <div
          class="thumbnail-item"
          :class="{
            'active': slideIndex === index,
            'selected': selectedSlidesIndex.includes(index),
          }"
          @mousedown="$event => handleClickSlideThumbnail($event, index)"
          v-contextmenu="contextmenusThumbnailItem"
        >
          <div class="label" :class="{ 'offset-left': index >= 99 }">{{ fillDigit(index + 1, 2) }}</div>
          <ThumbnailSlide class="thumbnail" :slide="element" :size="120" :visible="index < slidesLoadLimit" />
        </div>
      </template>
    </Draggable>
  </div>
</template>

<script lang="ts">
import { computed, defineComponent, ref } from 'vue'
import { storeToRefs } from 'pinia'
import { useMainStore, useSlidesStore, useKeyboardStore } from '@/store'
import { fillDigit } from '@/utils/common'
import { ContextmenuItem } from '@/components/Contextmenu/types'
import useSlideHandler from '@/hooks/useSlideHandler'
import useScreening from '@/hooks/useScreening'
import useLoadSlides from '@/hooks/useLoadSlides'

import Draggable from 'vuedraggable'
import ThumbnailSlide from '@/views/components/ThumbnailSlide/index.vue'
import LayoutPool from './LayoutPool.vue'

export default defineComponent({
  name: 'thumbnails',
  components: {
    Draggable,
    ThumbnailSlide,
    LayoutPool,
  },
  setup() {
    const mainStore = useMainStore()
    const slidesStore = useSlidesStore()
    const keyboardStore = useKeyboardStore()
    const { selectedSlidesIndex: _selectedSlidesIndex, thumbnailsFocus } = storeToRefs(mainStore)
    const { slides, slideIndex } = storeToRefs(slidesStore)
    const { ctrlKeyState, shiftKeyState } = storeToRefs(keyboardStore)

    const { slidesLoadLimit } = useLoadSlides()

    const selectedSlidesIndex = computed(() => [..._selectedSlidesIndex.value, slideIndex.value])

    const presetLayoutPopoverVisible = ref(false)

    const {
      copySlide,
      pasteSlide,
      createSlide,
      createSlideByTemplate,
      copyAndPasteSlide,
      deleteSlide,
      cutSlide,
      selectAllSlide,
    } = useSlideHandler()

    // 切换页面
    const changSlideIndex = (index: number) => {
      mainStore.setActiveElementIdList([])

      if (slideIndex.value === index) return
      slidesStore.updateSlideIndex(index)
    }

    // 点击缩略图
    const handleClickSlideThumbnail = (e: MouseEvent, index: number) => {
      const isMultiSelected = selectedSlidesIndex.value.length > 1

      if (isMultiSelected && selectedSlidesIndex.value.includes(index) && e.button !== 0) return

      // 按住Ctrl键，点选幻灯片，再次点击已选中的页面则取消选中
      if (ctrlKeyState.value) {
        if (slideIndex.value === index) {
          if (!isMultiSelected) return

          const newSelectedSlidesIndex = selectedSlidesIndex.value.filter(item => item !== index)
          mainStore.updateSelectedSlidesIndex(newSelectedSlidesIndex)
          changSlideIndex(selectedSlidesIndex.value[0])
        }
        else {
          if (selectedSlidesIndex.value.includes(index)) {
            const newSelectedSlidesIndex = selectedSlidesIndex.value.filter(item => item !== index)
            mainStore.updateSelectedSlidesIndex(newSelectedSlidesIndex)
          }
          else {
            const newSelectedSlidesIndex = [...selectedSlidesIndex.value, index]
            mainStore.updateSelectedSlidesIndex(newSelectedSlidesIndex)
            changSlideIndex(index)
          }
        }
      }
      // 按住Shift键，选择范围内的全部幻灯片
      else if (shiftKeyState.value) {
        if (slideIndex.value === index && !isMultiSelected) return

        let minIndex = Math.min(...selectedSlidesIndex.value)
        let maxIndex = index

        if (index < minIndex) {
          maxIndex = Math.max(...selectedSlidesIndex.value)
          minIndex = index
        }

        const newSelectedSlidesIndex = []
        for (let i = minIndex; i <= maxIndex; i++) newSelectedSlidesIndex.push(i)
        mainStore.updateSelectedSlidesIndex(newSelectedSlidesIndex)
        changSlideIndex(index)
      }
      // 正常切换页面
      else {
        mainStore.updateSelectedSlidesIndex([])
        changSlideIndex(index)
      }
    }

    // 设置缩略图工具栏聚焦状态（只有聚焦状态下，该部分的快捷键才能生效）
    const setThumbnailsFocus = (focus: boolean) => {
      if (thumbnailsFocus.value === focus) return
      mainStore.setThumbnailsFocus(focus)

      if (!focus) mainStore.updateSelectedSlidesIndex([])
    }

    // 拖拽调整顺序后进行数据的同步
    const handleDragEnd = (eventData: { newIndex: number; oldIndex: number }) => {
      const { newIndex, oldIndex } = eventData
      if (oldIndex === newIndex) return

      const _slides = JSON.parse(JSON.stringify(slides.value))
      const _slide = _slides[oldIndex]
      _slides.splice(oldIndex, 1)
      _slides.splice(newIndex, 0, _slide)
      slidesStore.setSlides(_slides)
      slidesStore.updateSlideIndex(newIndex)
    }

    const { enterScreening } = useScreening()

    const contextmenusThumbnails = (): ContextmenuItem[] => {
      return [
        {
          text: '粘贴',
          subText: 'Ctrl + V',
          handler: pasteSlide,
        },
        {
          text: '全选',
          subText: 'Ctrl + A',
          handler: selectAllSlide,
        },
        {
          text: '新建页面',
          subText: 'Enter',
          handler: createSlide,
        },
        {
          text: '开始演示',
          subText: 'Ctrl + F',
          handler: enterScreening,
        },
      ]
    }

    const contextmenusThumbnailItem = (): ContextmenuItem[] => {
      return [
        {
          text: '剪切',
          subText: 'Ctrl + X',
          handler: cutSlide,
        },
        {
          text: '复制',
          subText: 'Ctrl + C',
          handler: copySlide,
        },
        {
          text: '粘贴',
          subText: 'Ctrl + V',
          handler: pasteSlide,
        },
        {
          text: '全选',
          subText: 'Ctrl + A',
          handler: selectAllSlide,
        },
        { divider: true },
        {
          text: '新建页面',
          subText: 'Enter',
          handler: createSlide,
        },
        {
          text: '复制页面',
          subText: 'Ctrl + D',
          handler: copyAndPasteSlide,
        },
        {
          text: '删除页面',
          subText: 'Delete',
          handler: () => deleteSlide(),
        },
        { divider: true },
        {
          text: '从当前页演示',
          subText: 'Ctrl + F',
          handler: enterScreening,
        },
      ]
    }

    return {
      slides,
      slideIndex,
      selectedSlidesIndex,
      presetLayoutPopoverVisible,
      slidesLoadLimit,
      createSlide,
      createSlideByTemplate,
      setThumbnailsFocus,
      handleClickSlideThumbnail,
      contextmenusThumbnails,
      contextmenusThumbnailItem,
      fillDigit,
      handleDragEnd,
    }
  },
})
</script>

<style lang="scss" scoped>
.thumbnails {
  border-right: solid 1px $borderColor;
  background-color: #fff;
  display: flex;
  flex-direction: column;
  user-select: none;
}
.add-slide {
  height: 40px;
  font-size: 12px;
  display: flex;
  flex-shrink: 0;
  border-bottom: 1px solid $borderColor;
  cursor: pointer;

  .btn {
    flex: 1;
    display: flex;
    justify-content: center;
    align-items: center;

    &:hover {
      background-color: $lightGray;
    }
  }
  .select-btn {
    width: 30px;
    display: flex;
    justify-content: center;
    align-items: center;
    border-left: 1px solid $borderColor;

    &:hover {
      background-color: $lightGray;
    }
  }

  .icon {
    margin-right: 3px;
    font-size: 14px;
  }
}
.thumbnail-list {
  padding: 5px 0;
  flex: 1;
  overflow: auto;
}
.thumbnail-item {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 5px 0;

  .thumbnail {
    outline: 1px solid rgba($color: $themeColor, $alpha: .15);
  }

  &.active {
    .label {
      color: $themeColor;
    }
    .thumbnail {
      outline-color: $themeColor;
    }
  }
  &.selected {
    .thumbnail {
      outline-color: $themeColor;
    }
  }
}
.label {
  font-size: 12px;
  color: #999;
  width: 20px;
  cursor: grab;

  &.offset-left {
    position: relative;
    left: -4px;
  }

  &:active {
    cursor: grabbing;
  }
}
</style>