<template>
  <div class="shape-style-panel">
    <div class="title">
      <span>{{ lang.ssClickReplaceShape }}</span>
      <IconDown />
    </div>
    <div class="shape-pool">
      <div class="category" v-for="item in SHAPE_LIST" :key="item.type">
        <div class="shape-list">
          <ShapeItemThumbnail 
            class="shape-item"
            v-for="(shape, index) in item.children"
            :key="index"
            :shape="shape"
            @click="changeShape(shape)"
          />
        </div>
      </div>
    </div>

    <div class="row">
      <Select 
        style="flex: 1;" 
        :value="fillType" 
        @update:value="value => updateFillType(value as 'fill' | 'gradient' | 'pattern')"
        :options="[
          { label: lang.ssSolidFill, value: 'fill' },
          { label: lang.ssGradFill, value: 'gradient' },
          { label: lang.ssImgFill, value: 'pattern' },
        ]"
      />
      <div style="width: 10px;" v-if="fillType !== 'pattern'"></div>
      <Popover trigger="click" v-if="fillType === 'fill'" style="flex: 1;">
        <template #content>
          <ColorPicker
            :modelValue="fill"
            @update:modelValue="value => updateFill(value)"
          />
        </template>
        <ColorButton :color="fill" />
      </Popover>
      <Select 
        style="flex: 1;" 
        :value="gradient.type" 
        @update:value="value => updateGradient({ type: value as GradientType })"
        v-else-if="fillType === 'gradient'"
        :options="[
          { label: lang.ssLinearGrad, value: 'linear' },
          { label: lang.ssRadialGrad, value: 'radial' },
        ]"
      />
    </div>
    
    <template v-if="fillType === 'gradient'">
      <div class="row">
        <GradientBar
          :value="gradient.colors"
          :index="currentGradientIndex"
          @update:value="value => updateGradient({ colors: value })"
          @update:index="index => currentGradientIndex = index"
        />
      </div>
      <div class="row">
        <div style="width: 40%;">{{ lang.ssCurColorBlock }}</div>
        <Popover trigger="click" style="width: 60%;">
          <template #content>
            <ColorPicker
              :modelValue="gradient.colors[currentGradientIndex].color"
              @update:modelValue="value => updateGradientColors(value)"
            />
          </template>
          <ColorButton :color="gradient.colors[currentGradientIndex].color" />
        </Popover>
      </div>
      <div class="row" v-if="gradient.type === 'linear'">
        <div style="width: 40%;">{{ lang.ssGradAngle }}</div>
        <Slider
          style="width: 60%;"
          :min="0"
          :max="360"
          :step="15"
          :value="gradient.rotate"
          @update:value="value => updateGradient({ rotate: value as number })" 
        />
      </div>
    </template>
    
    <template v-if="fillType === 'pattern'">
      <div class="pattern-image-wrapper">
        <FileInput @change="files => uploadPattern(files)">
          <div class="pattern-image">
            <div class="content" :style="{ backgroundImage: `url(${pattern})` }">
              <IconPlus />
            </div>
          </div>
        </FileInput>
      </div>
    </template>

    <ElementFlip />

    <Divider />

    <template v-if="handleShapeElement.text?.content">
      <RichTextBase />
      <Divider />

      <RadioGroup 
        class="row" 
        button-style="solid" 
        :value="textAlign"
        @update:value="value => updateTextAlign(value as 'top' | 'middle' | 'bottom')"
      >
        <RadioButton value="top" v-tooltip="lang.ssAlignTop" style="flex: 1;"><IconAlignTextTopOne /></RadioButton>
        <RadioButton value="middle" v-tooltip="lang.ssAlignMiddle" style="flex: 1;"><IconAlignTextMiddleOne /></RadioButton>
        <RadioButton value="bottom" v-tooltip="lang.ssAlignBottom" style="flex: 1;"><IconAlignTextBottomOne /></RadioButton>
      </RadioGroup>

      <Divider />
    </template>

    <ElementOutline />
    <Divider />
    <ElementShadow />
    <Divider />
    <ElementOpacity />
    <Divider />

    <div class="row">
      <CheckboxButton
        v-tooltip="lang.ssFormatPainter"
        style="flex: 1;"
        :checked="!!shapeFormatPainter"
        @click="toggleShapeFormatPainter()"
        @dblclick="toggleShapeFormatPainter(true)"
      ><IconFormatBrush /> {{ lang.ssShapePainter }}</CheckboxButton>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { type Ref, ref, watch } from 'vue'
import { storeToRefs } from 'pinia'
import { useMainStore, useSlidesStore } from '@/store'
import type { GradientType, PPTShapeElement, Gradient, ShapeText } from '@/types/slides'
import { type ShapePoolItem, SHAPE_LIST, SHAPE_PATH_FORMULAS } from '@/configs/shapes'
import { getImageDataURL } from '@/utils/image'
import emitter, { EmitterEvents } from '@/utils/emitter'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
import useShapeFormatPainter from '@/hooks/useShapeFormatPainter'
import { lang } from '@/main'

import ElementOpacity from '../common/ElementOpacity.vue'
import ElementOutline from '../common/ElementOutline.vue'
import ElementShadow from '../common/ElementShadow.vue'
import ElementFlip from '../common/ElementFlip.vue'
import RichTextBase from '../common/RichTextBase.vue'
import ShapeItemThumbnail from '@/views/Editor/CanvasTool/ShapeItemThumbnail.vue'
import ColorButton from '@/components/ColorButton.vue'
import CheckboxButton from '@/components/CheckboxButton.vue'
import ColorPicker from '@/components/ColorPicker/index.vue'
import Divider from '@/components/Divider.vue'
import Slider from '@/components/Slider.vue'
import RadioButton from '@/components/RadioButton.vue'
import RadioGroup from '@/components/RadioGroup.vue'
import Select from '@/components/Select.vue'
import Popover from '@/components/Popover.vue'
import GradientBar from '@/components/GradientBar.vue'
import FileInput from '@/components/FileInput.vue'

const mainStore = useMainStore()
const slidesStore = useSlidesStore()
const { handleElement, handleElementId, shapeFormatPainter } = storeToRefs(mainStore)

const handleShapeElement = handleElement as Ref<PPTShapeElement>

const fill = ref<string>('#000')
const pattern = ref<string>('')
const gradient = ref<Gradient>({
  type: 'linear', 
  rotate: 0,
  colors: [
    { pos: 0, color: '#fff' },
    { pos: 100, color: '#fff' },
  ],
})
const fillType = ref('fill')
const textAlign = ref('middle')
const currentGradientIndex = ref(0)

watch(handleElement, () => {
  if (!handleElement.value || handleElement.value.type !== 'shape') return

  fill.value = handleElement.value.fill || '#fff'
  const defaultGradientColor = [
    { pos: 0, color: fill.value },
    { pos: 100, color: '#fff' },
  ]
  gradient.value = handleElement.value.gradient || { type: 'linear', rotate: 0, colors: defaultGradientColor }
  pattern.value = handleElement.value.pattern || ''
  fillType.value = (handleElement.value.pattern !== undefined) ? 'pattern' : (handleElement.value.gradient ? 'gradient' : 'fill')
  textAlign.value = handleElement.value?.text?.align || 'middle'

  if (handleElement.value.text?.content) {
    emitter.emit(EmitterEvents.SYNC_RICH_TEXT_ATTRS_TO_STORE)
  }
}, { deep: true, immediate: true })

watch(handleElementId, () => {
  currentGradientIndex.value = 0
})

const { addHistorySnapshot } = useHistorySnapshot()
const { toggleShapeFormatPainter } = useShapeFormatPainter()

const updateElement = (props: Partial<PPTShapeElement>) => {
  slidesStore.updateElement({ id: handleElementId.value, props })
  addHistorySnapshot()
}

// 设置填充类型：渐变、纯色
const updateFillType = (type: 'gradient' | 'fill' | 'pattern') => {
  if (type === 'fill') {
    slidesStore.removeElementProps({ id: handleElementId.value, propName: ['gradient', 'pattern'] })
    addHistorySnapshot()
  }
  else if (type === 'gradient') {
    currentGradientIndex.value = 0
    slidesStore.removeElementProps({ id: handleElementId.value, propName: 'pattern' })
    updateElement({ gradient: gradient.value })
  }
  else if (type === 'pattern') {
    slidesStore.removeElementProps({ id: handleElementId.value, propName: 'gradient' })
    updateElement({ pattern: '' })
  }
}

// 设置渐变填充
const updateGradient = (gradientProps: Partial<Gradient>) => {
  if (!gradient.value) return
  const _gradient = { ...gradient.value, ...gradientProps }
  updateElement({ gradient: _gradient })
}
const updateGradientColors = (color: string) => {
  const colors = gradient.value.colors.map((item, index) => {
    if (index === currentGradientIndex.value) return { ...item, color }
    return item
  })
  updateGradient({ colors })
}

// 上传填充图片
const uploadPattern = (files: FileList) => {
  const imageFile = files[0]
  if (!imageFile) return
  getImageDataURL(imageFile).then(dataURL => {
    pattern.value = dataURL
    updateElement({ pattern: dataURL })
  })
}

// 设置填充色
const updateFill = (value: string) => {
  updateElement({ fill: value })
}

// 修改形状
const changeShape = (shape: ShapePoolItem) => {
  const { width, height } = handleElement.value as PPTShapeElement
  const props: Partial<PPTShapeElement> = {
    viewBox: shape.viewBox,
    path: shape.path,
    special: shape.special,
  }
  if (shape.pathFormula) {
    props.pathFormula = shape.pathFormula
    props.viewBox = [width, height]

    const pathFormula = SHAPE_PATH_FORMULAS[shape.pathFormula]
    if ('editable' in pathFormula) {
      props.path = pathFormula.formula(width, height, pathFormula.defaultValue)
      props.keypoints = pathFormula.defaultValue
    }
    else props.path = pathFormula.formula(width, height)
  }
  else {
    props.pathFormula = undefined
    props.keypoints = undefined
  }
  updateElement(props)
}

const updateTextAlign = (align: 'top' | 'middle' | 'bottom') => {
  const _handleElement = handleElement.value as PPTShapeElement
  
  const defaultText: ShapeText = {
    content: '',
    defaultFontName: '',
    defaultColor: '#000',
    align: 'middle',
  }
  const _text = _handleElement.text || defaultText
  updateElement({ text: { ..._text, align } })
}
</script>

<style lang="scss" scoped>
.shape-style-panel {
  user-select: none;
}
.row {
  width: 100%;
  display: flex;
  align-items: center;
  margin-bottom: 10px;
}
.font-size-btn {
  padding: 0;
}
.title {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
}
.shape-pool {
  width: 235px;
  height: 150px;
  overflow: auto;
  padding: 5px;
  padding-right: 10px;
  border: 1px solid $borderColor;
  margin-bottom: 20px;
}
.shape-list {
  @include flex-grid-layout();
}
.shape-item {
  @include flex-grid-layout-children(6, 14%);

  height: 0;
  padding-bottom: 14%;
  flex-shrink: 0;
}

.pattern-image-wrapper {
  margin-bottom: 10px;
}
.pattern-image {
  height: 0;
  padding-bottom: 56.25%;
  border: 1px dashed $borderColor;
  border-radius: $borderRadius;
  position: relative;
  transition: all $transitionDelay;

  &:hover {
    border-color: $themeColor;
    color: $themeColor;
  }

  .content {
    @include absolute-0();

    display: flex;
    justify-content: center;
    align-items: center;
    background-position: center;
    background-size: contain;
    background-repeat: no-repeat;
    cursor: pointer;
  }
}
</style>