<template>
  <div class="image-style-panel">
    <div v-if="handleImageElement.src"
      class="origin-image"
      :style="{ backgroundImage: `url(${handleImageElement.src})` }"
    ></div>
    <Button class="full-width-btn" @click="getImgVis()"><IconTransform class="btn-icon"/> 替换图片</Button>
    <Button class="full-width-btn" @click="getPictDef()" :style="{'margin-bottom': mode==1?0:''}">处理图清晰度</Button>
    <Divider v-if="mode==1" />
    <div v-if="mode==1" class="row items-center">
      <div class="col">图层名称：</div>
      <el-input style="width:60%;" v-model="layerName" @input="updateLayerName"></el-input>
    </div>
    <Divider v-if="mode==1" />

    <ElementFlip />
    <div class="element-data-mapping">
      <divider />
      <div class="q-mb-md row items-center">
          <div class="text-small col">锁定裁剪</div>
          <el-checkbox v-model="ctrlKeyState" label="锁定裁剪比列" size="small" @change="getLockCutRatio"/>
      </div>
    </div>
    <ButtonGroup class="row" passive>
      <Button first style="width: calc(100% / 6 * 5);" @click="clipImage()"><IconTailoring class="btn-icon" /> 裁剪图片</Button>
      <Popover trigger="click" v-model:value="clipPanelVisible" style="width: calc(100% / 6);">
        <template #content>
          <div class="clip">
            <div class="title">按形状：</div>
            <div class="shape-clip">
              <div 
                class="shape-clip-item" 
                v-for="(item, key) in shapeClipPathOptions" 
                :key="key"
                @click="presetImageClip(key as string)"
              >
                <div class="shape" :style="{ clipPath: item.style }"></div>
              </div>
            </div>

            <template v-for="typeItem in ratioClipOptions" :key="typeItem.label">
              <div class="title" v-if="typeItem.label">按{{typeItem.label}}：</div>
              <ButtonGroup class="row">
                <Button 
                  style="flex: 1;"
                  v-for="item in typeItem.children"
                  :key="item.key"
                  @click="presetImageClip('rect', item.ratio)"
                >{{item.key}}</Button>
              </ButtonGroup>
            </template>
          </div>
        </template>
        <Button last class="popover-btn" style="width: 100%;"><IconDown /></Button>
      </Popover>
    </ButtonGroup>

    <ElementDataMapping v-if="mode==0||mode==2"></ElementDataMapping>

    <Divider />
    <ElementColorMask />
    <Divider />
    <ElementFilter />
    <Divider />
    <ElementOutline />
    <Divider />
    <ElementShadow />
    <Divider />
<!--     
    <FileInput @change="files => replaceImage(files)">
      <Button class="full-width-btn"><IconTransform class="btn-icon" /> 替换图片</Button>
    </FileInput> -->
    <Button class="full-width-btn" @click="resetImage()"><IconUndo class="btn-icon" /> 重置样式</Button>
    <Button class="full-width-btn" @click="setBackgroundImage()"><IconTheme class="btn-icon" /> 设为背景</Button>
    <!-- 上传图片 -->
    <UploadPicture v-show="imgReplaceVisible"></UploadPicture>

    <!-- 图片处理对比 -->
    <imgArticContr v-if="DefinitionDatas" :width="imgWidth" :height="imgHeigth"
    :newImg="DefinitionDatas"
    @close="DefinitionDatas=null"
    @success="DefinitionDatas=null">
      <template #left>
        <span style="position: absolute;left: 10px;top:10px;background: #fff;border-radius: 3px;padding:0 5px;width: 38px;">原图</span>
        <img :src="handleImageElement.src" class="images" :style="{width: imgWidth+'px',height: imgHeigth+'px'}" />
      </template>
      <template #right>
        <span style="position: absolute;right: 10px;top:10px;background: #fff;border-radius: 3px;padding:0 5px;width: 53px;">高清图</span>
        <img :src="'data:image/png;base64,'+DefinitionDatas" class="images" :style="{width: imgWidth+'px',height: imgHeigth+'px'}" />
      </template>
    </imgArticContr>
  </div>
</template>

<script lang="ts" setup>
import { type Ref, ref, provide, reactive } from 'vue'
import { storeToRefs } from 'pinia'
import { useMainStore, useSlidesStore, useScreenStore, useKeyboardStore } from '@/store'
import type { PPTImageElement, SlideBackground } from '@/types/slides'
import { CLIPPATHS } from '@/configs/imageClip'
import { getImageDataURL } from '@/utils/image'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'

import ElementOutline from '../common/ElementOutline.vue'
import ElementShadow from '../common/ElementShadow.vue'
import ElementFlip from '../common/ElementFlip.vue'
import ElementFilter from '../common/ElementFilter.vue'
import ElementColorMask from '../common/ElementColorMask.vue'
import ElementDataMapping from '../common/ElementDataMapping.vue'
import FileInput from '@/components/FileInput.vue'
import Divider from '@/components/Divider.vue'
import Button from '@/components/Button.vue'
import ButtonGroup from '@/components/ButtonGroup.vue'
import Popover from '@/components/Popover.vue'
import UploadPicture from '../../CanvasTool/UploadPicture.vue'

import imgArticContr from '@/components/CloudDisk/imgArticContr.vue'
import CloudDiskService from '@/services/CloudDiskService'
import { ApiResult } from "@/configs/axios";
import AliyunUpload from '@/utils/upload/aliyun'
import { ElLoading } from "element-plus";
import FileService from '@/services/FileService'

const shapeClipPathOptions = CLIPPATHS
const ratioClipOptions = [
  {
    label: '纵横比（正方形）',
    children: [
      { key: '1:1', ratio: 1 / 1 },
    ],
  },
  {
    label: '纵横比（纵向）',
    children: [
      { key: '2:3', ratio: 3 / 2 },
      { key: '3:4', ratio: 4 / 3 },
      { key: '3:5', ratio: 5 / 3 },
      { key: '4:5', ratio: 5 / 4 },
    ],
  },
  {
    label: '纵横比（横向）',
    children: [
      { key: '3:2', ratio: 2 / 3 },
      { key: '4:3', ratio: 3 / 4 },
      { key: '5:3', ratio: 3 / 5 },
      { key: '5:4', ratio: 4 / 5 },
    ],
  },
  {
    children: [
      { key: '16:9', ratio: 9 / 16 },
      { key: '16:10', ratio: 10 / 16 },
    ],
  },
]

const mainStore = useMainStore()
const slidesStore = useSlidesStore()
const keyboardStore = useKeyboardStore()
const { handleElement, handleElementId } = storeToRefs(mainStore)
const { currentSlide } = storeToRefs(slidesStore)
const { ctrlKeyState } = storeToRefs(useKeyboardStore())
const layerName = ref(handleElement.value?.layerName??'')


const handleImageElement = handleElement as Ref<PPTImageElement>

const clipPanelVisible = ref(false)

const { addHistorySnapshot } = useHistorySnapshot()

const { imgReplaceVisible, model } = storeToRefs(useScreenStore())
const mode = model.value??1

provide('imgType',2)

const DefinitionLoading = ref(false)
const DefinitionDatas = ref('' as any)
const DefinParams = reactive({
  basestr: '',
  extname: '',
  url: '',
})
const imgWidth = ref(500)
const imgHeigth = ref(0)

const getPictDef = async () =>{
  await getImgSize()
  if(handleImageElement.value.src.startsWith("data:image")){
    let name = new Date().getTime()+".jpg"
    const file = dataURLtoFile(handleImageElement.value.src, name)
    let url = await AliyunUpload.UploadAsync(file,`Feature/CoverImg_${name}`)
    DefinParams.url= url
  }else DefinParams.url = handleImageElement.value.src
  let files = DefinParams.url.split('/')
  DefinParams.extname = files[files.length-1]
  DefinitionImg()
}

const DefinitionImg = async () =>{
  if(DefinitionLoading.value) return
  DefinitionLoading.value = true
  const loadingObj = ElLoading.service({
      text:'正在处理图的清晰度',
      lock:true
  })
  try {
      const datasRes = await CloudDiskService.BaiduImageDefinition(DefinParams);
      if (datasRes.data.resultCode==ApiResult.SUCCESS) {
          DefinitionDatas.value = datasRes.data.data 
      }
      DefinitionLoading.value = false
      loadingObj.close()
  } catch (error) {
    DefinitionLoading.value = false
    loadingObj.close()
  }
    
}
const getImgSize = async () => {
  let TempSize = await FileService.getImageSizeWithoutDownloading(handleImageElement.value.src)
  let ratio = TempSize.width/imgWidth.value
  imgHeigth.value = TempSize.height/ratio
}

const getLockCutRatio = () =>{
  keyboardStore.setCtrlKeyState(ctrlKeyState.value)
}

const getImgVis = () =>{
  imgReplaceVisible.value = true
}

// 打开自由裁剪
const clipImage = () => {
  mainStore.setClipingImageElementId(handleElementId.value)
  clipPanelVisible.value = false
}

// 获取原始图片的位置大小
const getImageElementDataBeforeClip = () => {
  const _handleElement = handleElement.value as PPTImageElement

  // 图片当前的位置大小和裁剪范围
  const imgWidth = _handleElement.width
  const imgHeight = _handleElement.height
  const imgLeft = _handleElement.left
  const imgTop = _handleElement.top
  const originClipRange: [[number, number], [number, number]] = _handleElement.clip ? _handleElement.clip.range : [[0, 0], [100, 100]]

  const originWidth = imgWidth / ((originClipRange[1][0] - originClipRange[0][0]) / 100)
  const originHeight = imgHeight / ((originClipRange[1][1] - originClipRange[0][1]) / 100)
  const originLeft = imgLeft - originWidth * (originClipRange[0][0] / 100)
  const originTop = imgTop - originHeight * (originClipRange[0][1] / 100)

  return {
    originClipRange,
    originWidth,
    originHeight,
    originLeft,
    originTop,
  }
}

// 预设裁剪
const presetImageClip = (shape: string, ratio = 0) => {
  if(shape=='ellipse') ratio = 1
  const _handleElement = handleElement.value as PPTImageElement

  const {
    originClipRange,
    originWidth,
    originHeight,
    originLeft,
    originTop,
  } = getImageElementDataBeforeClip()
  
  // 纵横比裁剪（形状固定为矩形）
  if (ratio) {
    const imageRatio = originHeight / originWidth

    const min = 0
    const max = 100
    let range: [[number, number], [number, number]]

    if (imageRatio > ratio) {
      const distance = ((1 - ratio / imageRatio) / 2) * 100
      range = [[min, distance], [max, max - distance]]
    }
    else {
      const distance = ((1 - imageRatio / ratio) / 2) * 100
      range = [[distance, min], [max - distance, max]]
    }
    slidesStore.updateElement({
      id: handleElementId.value,
      props: {
        clip: { ..._handleElement.clip, shape, range },
        left: originLeft + originWidth * (range[0][0] / 100),
        top: originTop + originHeight * (range[0][1] / 100),
        width: originWidth * (range[1][0] - range[0][0]) / 100,
        height: originHeight * (range[1][1] - range[0][1]) / 100,
      },
    })
  }
  // 形状裁剪（保持当前裁剪范围）
  else {
    slidesStore.updateElement({
      id: handleElementId.value,
      props: {
        clip: { ..._handleElement.clip, shape, range: originClipRange }
      },
    })
  }
  clipImage()
  addHistorySnapshot()
}

// 替换图片（保持当前的样式）
const replaceImage = (files: FileList) => {
  const imageFile = files[0]
  if (!imageFile) return
  getImageDataURL(imageFile).then(dataURL => {
    const props = { src: dataURL }
    slidesStore.updateElement({ id: handleElementId.value, props })
  })
  addHistorySnapshot()
}

// 重置图片：清除全部样式
const resetImage = () => {
  const _handleElement = handleElement.value as PPTImageElement

  if (_handleElement.clip) {
    const {
      originWidth,
      originHeight,
      originLeft,
      originTop,
    } = getImageElementDataBeforeClip()

    slidesStore.updateElement({
      id: handleElementId.value,
      props: {
        left: originLeft,
        top: originTop,
        width: originWidth,
        height: originHeight,
      },
    })
  }

  slidesStore.removeElementProps({
    id: handleElementId.value,
    propName: ['clip', 'outline', 'flip', 'shadow', 'filters', 'colorMask'],
  })
  addHistorySnapshot()
}

const updateLayerName = (e:any)=>{
  slidesStore.updateElement({
    id: handleElementId.value,
    props: { layerName: e }
  })
}

// 将图片设置为背景
const setBackgroundImage = () => {
  const _handleElement = handleElement.value as PPTImageElement

  const background: SlideBackground = {
    ...currentSlide.value.background,
    type: 'image',
    image: _handleElement.src,
    imageSize: 'cover',
  }
  slidesStore.updateSlide({ background })
  addHistorySnapshot()
}

const initMapping = ()=>{
  if(handleElement.value && !handleElement.value.dataMapping && 'TemplateDataSource' in handleElement.value && handleElement.value.TemplateDataSource){
    if(handleElement.value.TemplateDataSource.index!=null && handleElement.value.TemplateDataSource.Content){
      //找出同类
      const resolveElemnts = slidesStore.currentSlide.elements.filter(x=>x.TemplateDataSource && x.TemplateDataSource.index== handleElement.value.TemplateDataSource.index && x.TemplateDataSource.Content && !x.dataMapping)
      if(resolveElemnts){
        resolveElemnts.forEach(x=>{
          const props = {
            below: x.TemplateDataSource.index,
            dataMapping: {
              id: 0,
              filed: x.TemplateDataSource.Content.split('.').reverse()[0],
              name: ''
            }
          }
          slidesStore.updateElement({ id: x.id, props })
        })
        addHistorySnapshot()
      }
      
    }
  }
}
initMapping()
</script>

<style lang="scss" scoped>
.row {
  width: 100%;
  display: flex;
  align-items: center;
  margin-bottom: 10px;
}
.switch-wrapper {
  text-align: right;
}
.origin-image {
  height: 100px;
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  background-color: $lightGray;
  margin-bottom: 10px;
}
.full-width-btn {
  width: 100%;
  margin-bottom: 10px;
}
.btn-icon {
  margin-right: 3px;
}

.clip {
  width: 260px;
  font-size: 12px;

  .title {
    margin-bottom: 5px;
  }
}
.shape-clip {
  margin-bottom: 10px;

  @include flex-grid-layout();
}
.shape-clip-item {
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;

  @include flex-grid-layout-children(5, 16%);

  &:hover .shape {
    background-color: #ccc;
  }

  .shape {
    width: 40px;
    height: 40px;
    background-color: #e1e1e1;
  }
}
.popover-btn {
  padding: 0 3px;
}
</style>