<template>
  <toolbar-base :options="options">
    <template #default>
      <div class="toolbar-wrap">
        <div class="toolbar-icon-wrap">
          <span
            v-for="(item, index) in state.media"
            :key="index"
            :class="['icon', { active: state.activeIndex === index, 'is-rotate': item.view === 'lanMobile' }]"
            @click="setViewPort(item)"
          >
            <tiny-popover
              trigger="hover"
              width="260"
              append-to-body
              :open-delay="1000"
              popper-class="media-icon-popover"
            >
              <div class="media-content">
                <div class="media-title">
                  <div>
                    {{ item.title }}
                    <span v-if="item.subTitle" class="sub-title">
<svg-icon v-if="item.view === 'desktop'" name="stars"></svg-icon>
                      <span>{{ item.subTitle }}</span
                      >)
                    </span>
                  </div>
                </div>
                <div class="content">{{ item.content }}</div>
              </div>
              <template #reference>
                <svg-icon :name="item.liked" class="media-icon"></svg-icon>
              </template>
            </tiny-popover>
          </span>
        </div>
        <tiny-popover v-if="isCanvas" width="200" trigger="click" popper-class="toolbar-media-popper">
          <template #reference>
            <span class="reference-text" title="画布设置">
              <span>
                <span>{{ parseInt(state.width) }}</span>
                <span class="symbol">px</span>
              </span>
              <span>
                <span>{{ scale.toFixed(2) }}</span>
                <span class="symbol">%</span>
              </span>
            </span>
          </template>
          <div class="content-wrap text-content">
            <div class="title text-title">{{ state.textData.title }}</div>
            <div class="setting">
              <div>
                <label>{{ state.textData.width }}</label>
                <tiny-input v-model="state.width" @change="widthChange">
                  <template #suffix>
                    <span>px</span>
                  </template>
                </tiny-input>
              </div>
              <div>
                <label>{{ state.textData.scale }}</label>
                <tiny-input v-model="state.scaleValue" :readonly="state.readonly" @change="scaleChange">
                  <template #suffix>
                    <span>%</span>
                  </template>
                </tiny-input>
              </div>
              <div>
                <label>{{ '自由布局' }}</label>
                <tiny-switch v-model="isAbsolute" @change="changeCanvasType"></tiny-switch>
              </div>
            </div>
          </div>
        </tiny-popover>
      </div>
    </template>
  </toolbar-base>
</template>

<script lang="ts">
/* metaService: engine.toolbars.media.Main */
import { ref, reactive, computed, toRaw, watchEffect, onMounted, onUnmounted, watch } from 'vue'
import { Popover, Input, Switch } from '@opentiny/vue'
import { IconWebPlus } from '@opentiny/vue-icon'
import { useLayout, useCanvas } from '@opentiny/tiny-engine-meta-register'
import { ToolbarBase } from '@opentiny/tiny-engine-common'
import type { Component } from 'vue'

export default {
  components: {
    TinyPopover: Popover as Component,
    TinyInput: Input,
    TinySwitch: Switch,
    ToolbarBase
  },
  props: {
    data: {
      type: Object,
      default: () => ({})
    },
    isCanvas: {
      type: Boolean,
      default: true
    },
    options: {
      type: Object,
      default: () => ({})
    }
  },
  setup(props, { emit }) {
    let timer: any = null
    let prevWidthVal = ''
    let prevScaleVal = ''
    const { layoutState } = useLayout()
    const visible = ref(false)
    const active = ref(false)
    const flag = ref(false)
    const { getCanvasType } = useCanvas().canvasApi.value
    const isAbsolute = ref(getCanvasType?.() === 'absolute')

    const dimension = computed(() => useLayout().getDimension())
    const scale = computed(() => dimension.value.scale * 100)

    const state = reactive({
      activeIndex: 0,
      guideValue: '',
      width: '' as string | number,
      scaleValue: '' as string | number,
      readonly: false,
      viewWidth: null,
      moreData: {
        title: '添加大断点',
        list: [
          {
            icon: IconWebPlus(),
            text: '1280px'
          },
          {
            icon: IconWebPlus(),
            text: '1440px'
          },
          {
            icon: IconWebPlus(),
            text: '1920px'
          }
        ],
        tips: '将鼠标悬停在断点上以了解更多信息'
      },
      textData: {
        title: '画布设置',
        width: '宽度',
        scale: '缩放',
        list: [
          {
            text: '自由布局'
          }
        ],
        vision: '视觉预览'
      },
      guideOptions: [
        {
          value: '选项1',
          label: 'No guide'
        },
        {
          value: '选项2',
          label: 'Line guide(960px)'
        },
        {
          value: '选项3',
          label: 'Filled guide(960px)'
        }
      ],
      media: [
        {
          idx: 0,
          view: 'mdx',
          icon: 'IconDesktopView',
          liked: 'desktop-large',
          width: '1920px',
          minWidth: '1200px',
          maxWidth: '1920px',
          title: '大屏',
          subTitle: '1200px 及以上',
          content: '此处添加的样式将适用于 1200 像素及以上,除非它们在更大的断点处进行编辑。',
          enContent: 'Style added here will apply at 1200px and up,unless they′re edited at a larger breakpoint.'
        },
        {
          idx: 1,
          view: 'desktop',
          icon: 'IconDesktopView',
          liked: 'laptop-cut-corner',
          width: '1200px',
          minWidth: '992px',
          maxWidth: '1200px',
          title: 'PC 端',
          subTitle: '基本断点',
          content: '桌面端样式适用于所有断点,除非它们在更大或更小的断点处进行编辑,在这里开始你的布局。',
          enContent:
            'Desktop styles apply at all breakpoints,unless they′re edited at a larger or smaller breakpoints. Start your stying here.'
        },
        {
          idx: 2,
          view: 'tablet',
          icon: 'IconTabletView',
          liked: 'tablet-portrait',
          width: '992px',
          minWidth: '768px',
          maxWidth: '992px',
          title: '平板',
          subTitle: '992px 及以下',
          content: '此处添加的样式将适用于 992 像素及以下,除非它们在较小的断点处进行编辑。',
          enContent: 'styles added here will apply at 992px and down,unless they′re edited at smaller breakpoints.'
        },
        {
          idx: 3,
          view: 'lanMobile',
          icon: 'IconMobileView',
          liked: 'mobile-landscape',
          width: '768px',
          minWidth: '480px',
          maxWidth: '768px',
          title: '手机横屏',
          subTitle: '768px 及以下',
          content: '此处添加的样式将适用于 768 像素及以下,除非它们在较小的断点处进行编辑。',
          enContent: 'styles added here will apply at 768px and down,unless they′re edited at smaller breakpoints.'
        },
        {
          idx: 4,
          view: 'mobile',
          icon: 'IconMobileView',
          liked: 'mobile-portrai',
          width: '480px',
          minWidth: '240px',
          maxWidth: '480px',
          title: '手机竖屏',
          subTitle: '480px 及以下',
          content: '此处添加的样式将适用于 480 像素及以下。',
          enContent: 'styles added here will apply at 480px and down.'
        }
      ]
    })

    const hide = () => {
      active.value = false
    }

    const showTips = () => {
      timer = setTimeout(() => {
        visible.value = true
      }, 1000)
    }

    const hideTips = () => {
      visible.value = false
      clearTimeout(timer)
    }

    const showPopover = () => {
      layoutState.toolbars.visiblePopover = true
      flag.value = true
    }

    const hidePopover = () => {
      layoutState.toolbars.visiblePopover = false
      flag.value = false
    }

    const closePopover = (e: any) => {
      const ele = document.querySelector('.reference-text')
      const isChild = ele?.contains(e.target)

      if (ele !== e.target && !isChild) {
        layoutState.toolbars.visiblePopover = false
      }
    }

    const mediaMap = state.media.reduce((output, obj, index) => {
      output[obj.view] = { ...toRaw(obj), index }

      return output
    }, {})

    const setViewPort = (item: any) => {
      if (props.isCanvas) {
        useLayout().setDimension({
          deviceType: item.view,
          width: item.width,
          minWidth: item.minWidth,
          maxWidth: item.maxWidth
        })
      } else {
        state.activeIndex = item.idx
        emit('setViewPort', item.width)
      }
    }

    const activeView = (val: number, type: string) => {
      const item = mediaMap[type]
      useLayout().setDimension({
        deviceType: item.view,
        width: val ? `${val}px` : item.width,
        minWidth: item.minWidth,
        maxWidth: item.maxWidth
      })
    }

    const breakpoints = [
      { type: 'mobile', min: 240, max: 480 },
      { type: 'lanMobile', min: 480, max: 768 },
      { type: 'tablet', min: 768, max: 992 },
      { type: 'desktop', min: 992, max: 1200 },
      { type: 'mdx', min: 1200, max: 1920 }
    ]

    const widthChange = (val: string) => {
      const reg = /^\d+$/

      if (!String(val).match(reg)) {
        state.width = prevWidthVal ? prevWidthVal : parseInt(dimension.value.width, 10)
      } else if (Number(val) < 240) {
        state.width = 240
      } else if (Number(val) > 1920) {
        state.width = 1920
      } else {
        state.width = val
      }

      const width = Number(state.width)
      const type = breakpoints.find((item) => item.min <= width && width <= item.max)?.type || 'desktop'
      activeView(width, type)
    }

    const scaleChange = (val: string) => {
      const item = mediaMap['mdx']
      const reg = /^\d+(\.\d+)?$/

      if (!String(val).match(reg)) {
        state.scaleValue = prevScaleVal ? prevScaleVal : parseInt(item.scale)
      } else if (Number(val) > 100) {
        state.scaleValue = 100
      } else if (Number(val) < 20) {
        state.scaleValue = 20
      } else {
        state.scaleValue = val
      }
      state.scaleValue = Number(state.scaleValue).toFixed(2)

      useLayout().setDimension({
        scale: Number(state.scaleValue) / 100
      })
    }

    const changeCanvasType = (value) => {
      const { setCanvasType } = useCanvas().canvasApi.value
      setCanvasType(value ? 'absolute' : 'normal')
    }

    watch(
      () => dimension.value.deviceType,
      (deviceType) => {
        state.activeIndex = mediaMap[deviceType].index
        state.readonly = deviceType !== 'mdx'
      },
      { immediate: true }
    )

    watchEffect(() => {
      state.scaleValue = scale.value.toFixed(2)
      prevScaleVal = scale.value
    })

    watch(
      () => dimension.value.width,
      (width) => {
        const newWidth = parseInt(width, 10)
        if (Number.isInteger(newWidth)) {
          state.width = newWidth
          prevWidthVal = newWidth
        }
      }
    )

    onMounted(() => {
      document.addEventListener('click', closePopover)
    })

    onUnmounted(() => {
      document.removeEventListener('click', closePopover)
    })

    // 初始化 viewpoint
    const mode = dimension.value.deviceType || 'desktop'
    setViewPort(mediaMap[mode])

    return {
      scale,
      state,
      active,
      flag,
      hide,
      layoutState,
      visible,
      showTips,
      hideTips,
      timer,
      dimension,
      setViewPort,
      showPopover,
      hidePopover,
      widthChange,
      scaleChange,
      isAbsolute,
      changeCanvasType
    }
  }
}
</script>

<style lang="less" scoped>
.toolbar-wrap {
  display: flex;
  align-items: center;

  .reference-text {
    cursor: pointer;
    height: var(--base-top-panel-height);
    line-height: var(--base-top-panel-height);
    padding: 0 7px;
    color: var(--te-toolbars-media-text-color-secondary);
    display: inline-block;

    & > span {
      &:last-child {
        margin-left: 8px;
      }
    }
  }

  .toolbar-icon-wrap {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    gap: 6px;
    .icon {
      width: 24px;
      height: 24px;
      display: inline-flex;
      justify-content: center;
      align-items: center;
      border-radius: 4px;

      svg {
        cursor: pointer;
        color: var(--te-toolbars-media-text-color-primary);
        outline: none;
        width: 18px;
        height: 18px;
        margin-top: -0.5px;
      }

      &.active,
      &:hover {
        background: var(--te-toolbars-media-bg-color-active);
      }
      &.active {
        svg {
          color: var(--te-toolbars-media-text-color-checked);
        }
      }
    }
  }
  .more-setting {
    .setting-item {
      display: flex;
      justify-content: space-between;
      padding: 12px;
    }
  }
}
.media-content {
  line-height: 18px;
  .media-title {
    font-weight: 600;
  }
  .content {
    color: var(--te-toolbars-media-text-color-secondary);
  }
}
.setting-content {
  padding: 12px 8px;
}

.content-wrap {
  .title {
    font-weight: 600;
    margin-bottom: 16px;
  }

  .setting {
    display: flex;
    flex-direction: column;
    gap: 12px;
    div {
      display: flex;
      align-items: center;
      justify-content: space-between;
      label {
        color: var(--te-toolbars-media-text-color-secondary);
        min-width: 64px;
      }
      &:last-child {
        justify-content: flex-start;
      }
    }
  }
}
</style>