import { computed } from 'vue'
import { storeToRefs } from 'pinia'
import { useMainStore, useSlidesStore } from '@/store'
import type { PPTElement } from '@/types/slides'
import { getElementRange, getElementListRange, getRectRotatedOffset } from '@/utils/element'
import useHistorySnapshot from './useHistorySnapshot'

interface ElementItem {
  min: number
  max: number
  el: PPTElement
}

interface GroupItem {
  groupId: string
  els: PPTElement[]
}

interface GroupElementsItem {
  min: number
  max: number
  els: PPTElement[]
}

type Item = ElementItem | GroupElementsItem

interface ElementWithPos {
  pos: number
  el: PPTElement
}

interface LastPos {
  min: number
  max: number
}

export default () => {
  const slidesStore = useSlidesStore()
  const { activeElementIdList, activeElementList } = storeToRefs(useMainStore())
  const { currentSlide } = storeToRefs(slidesStore)

  const { addHistorySnapshot } = useHistorySnapshot()

  const displayItemCount = computed(() => {
    let count = 0
    const groupIdList: string[] = []
    for (const el of activeElementList.value) {
      if (!el.groupId) count += 1
      else if (!groupIdList.includes(el.groupId)) {
        groupIdList.push(el.groupId)
        count += 1
      }
    }
    return count
  })
  // 水平均匀排列
  const uniformHorizontalDisplay = () => {
    const { minX, maxX } = getElementListRange(activeElementList.value)
    const copyOfActiveElementList: PPTElement[] = JSON.parse(JSON.stringify(activeElementList.value))
    const newElementList: PPTElement[] = JSON.parse(JSON.stringify(currentSlide.value.elements))

    // 分别获取普通元素和组合元素集合，并记录下每一项的范围
    const singleElemetList: ElementItem[] = []
    let groupList: GroupItem[] = []
    for (const el of copyOfActiveElementList) {
      if (!el.groupId) {
        const { minX, maxX } = getElementRange(el)
        singleElemetList.push({ min: minX, max: maxX, el })
      }
      else {
        const groupEl = groupList.find(item => item.groupId === el.groupId)
        if (!groupEl) groupList.push({ groupId: el.groupId, els: [el] })
        else {
          groupList = groupList.map(item => item.groupId === el.groupId ? { ...item, els: [...item.els, el] } : item)
        }
      }
    }
    const formatedGroupList: GroupElementsItem[] = []
    for (const groupItem of groupList) {
      const { minX, maxX } = getElementListRange(groupItem.els)
      formatedGroupList.push({ min: minX, max: maxX, els: groupItem.els })
    }

    // 将普通元素和组合元素集合组合在一起，然后将每一项按位置（从左到右）排序
    const list: Item[] = [...singleElemetList, ...formatedGroupList]
    list.sort((itemA, itemB) => itemA.min - itemB.min)

    // 计算元素均匀分布所需要的间隔：
    // (所选元素整体范围 - 所有所选元素宽度和) / (所选元素数 - 1)
    let totalWidth = 0
    for (const item of list) {
      const width = item.max - item.min
      totalWidth += width
    }
    const span = ((maxX - minX) - totalWidth) / (list.length - 1)

    // 按位置顺序依次计算每一个元素的目标位置
    // 第一项中的元素即为起点，无需计算
    // 从第二项开始，每一项的位置应该为：上一项位置 + 上一项宽度 + 间隔
    // 注意此处计算的位置（pos）并非元素最终的left值，而是目标位置范围最小值（元素旋转后的left值 ≠ 范围最小值）
    const sortedElementData: ElementWithPos[] = []

    const firstItem = list[0]
    let lastPos: LastPos = { min: firstItem.min, max: firstItem.max }

    if ('el' in firstItem) {
      sortedElementData.push({ pos: firstItem.min, el: firstItem.el })
    }
    else {
      for (const el of firstItem.els) {
        const { minX: pos } = getElementRange(el)
        sortedElementData.push({ pos, el })
      }
    }

    for (let i = 1; i < list.length; i++) {
      const item = list[i]
      const lastWidth = lastPos.max - lastPos.min
      const currentPos = lastPos.min + lastWidth + span
      const currentWidth = item.max - item.min
      lastPos = { min: currentPos, max: currentPos + currentWidth }

      if ('el' in item) {
        sortedElementData.push({ pos: currentPos, el: item.el })
      }
      else {
        for (const el of item.els) {
          const { minX } = getElementRange(el)
          const offset = minX - item.min
          sortedElementData.push({ pos: currentPos + offset, el })
        }
      }
    }

    // 根据目标位置计算元素最终目标left值
    // 对于旋转后的元素，需要计算旋转前后left的偏移来做校正
    for (const element of newElementList) {
      if (!activeElementIdList.value.includes(element.id)) continue

      for (const sortedItem of sortedElementData) {
        if (sortedItem.el.id === element.id) {
          if ('rotate' in element && element.rotate) {
            const { offsetX } = getRectRotatedOffset({
              left: element.left,
              top: element.top,
              width: element.width,
              height: element.height,
              rotate: element.rotate,
            })
            element.left = sortedItem.pos - offsetX
          }
          else element.left = sortedItem.pos
        }
      }
    }

    slidesStore.updateSlide({ elements: newElementList })
    addHistorySnapshot()
  }

  // 垂直均匀排列（逻辑类似水平均匀排列方法）
  const uniformVerticalDisplay = () => {
    const { minY, maxY } = getElementListRange(activeElementList.value)
    const copyOfActiveElementList: PPTElement[] = JSON.parse(JSON.stringify(activeElementList.value))
    const newElementList: PPTElement[] = JSON.parse(JSON.stringify(currentSlide.value.elements))

    const singleElemetList: ElementItem[] = []
    let groupList: GroupItem[] = []
    for (const el of copyOfActiveElementList) {
      if (!el.groupId) {
        const { minY, maxY } = getElementRange(el)
        singleElemetList.push({ min: minY, max: maxY, el })
      }
      else {
        const groupEl = groupList.find(item => item.groupId === el.groupId)
        if (!groupEl) groupList.push({ groupId: el.groupId, els: [el] })
        else {
          groupList = groupList.map(item => item.groupId === el.groupId ? { ...item, els: [...item.els, el] } : item)
        }
      }
    }
    const formatedGroupList: GroupElementsItem[] = []
    for (const groupItem of groupList) {
      const { minY, maxY } = getElementListRange(groupItem.els)
      formatedGroupList.push({ min: minY, max: maxY, els: groupItem.els })
    }

    const list: Item[] = [...singleElemetList, ...formatedGroupList]
    list.sort((itemA, itemB) => itemA.min - itemB.min)

    let totalHeight = 0
    for (const item of list) {
      const height = item.max - item.min
      totalHeight += height
    }
    const span = ((maxY - minY) - totalHeight) / (list.length - 1)

    const sortedElementData: ElementWithPos[] = []

    const firstItem = list[0]
    let lastPos: LastPos = { min: firstItem.min, max: firstItem.max }

    if ('el' in firstItem) {
      sortedElementData.push({ pos: firstItem.min, el: firstItem.el })
    }
    else {
      for (const el of firstItem.els) {
        const { minY: pos } = getElementRange(el)
        sortedElementData.push({ pos, el })
      }
    }

    for (let i = 1; i < list.length; i++) {
      const item = list[i]
      const lastHeight = lastPos.max - lastPos.min
      const currentPos = lastPos.min + lastHeight + span
      const currentHeight = item.max - item.min
      lastPos = { min: currentPos, max: currentPos + currentHeight }

      if ('el' in item) {
        sortedElementData.push({ pos: currentPos, el: item.el })
      }
      else {
        for (const el of item.els) {
          const { minY } = getElementRange(el)
          const offset = minY - item.min
          sortedElementData.push({ pos: currentPos + offset, el })
        }
      }
    }

    for (const element of newElementList) {
      if (!activeElementIdList.value.includes(element.id)) continue

      for (const sortedItem of sortedElementData) {
        if (sortedItem.el.id === element.id) {
          if ('rotate' in element && element.rotate) {
            const { offsetY } = getRectRotatedOffset({
              left: element.left,
              top: element.top,
              width: element.width,
              height: element.height,
              rotate: element.rotate,
            })
            element.top = sortedItem.pos - offsetY
          }
          else element.top = sortedItem.pos
        }
      }
    }

    slidesStore.updateSlide({ elements: newElementList })
    addHistorySnapshot()
  }

  return {
    displayItemCount,
    uniformHorizontalDisplay,
    uniformVerticalDisplay,
  }
}