<template>
  <div class="echarts" />
</template>

<script setup>
  import { onMounted } from 'vue'
  import * as echarts from 'echarts'
  import theme from './theme/vab-echarts-theme.json'
  import debounce from 'lodash/debounce'
  import { addListener, removeListener } from 'resize-detector'
  import { useThemeStore } from '@/stores/modules/theme'

  const INIT_TRIGGERS = ['theme', 'initOptions', 'autoResize']
  const REWATCH_TRIGGERS = ['manualUpdate', 'watchShallow']

  const themeStore = useThemeStore()
  const props = defineProps({
    option: {
      type: Object,
      default: () => {},
    },
    theme: {
      type: [String, Object],
      default: () => {},
    },
    initOptions: {
      type: Object,
      default: () => {},
    },
    group: {
      type: String,
      default: '',
    },
    autoResize: {
      type: Boolean,
      default: true,
    },
    watchShallow: {
      type: Boolean,
      default: false,
    },
    manualUpdate: {
      type: Boolean,
      default: false,
    },
  })
  const state = reactive({
    chart: null,
    lastArea: 0,
    manualOptions: {},
  })

  const { chart, lastArea, manualOptions } = toRefs(state)

  const { option, theme, group, initOptions, autoResize, watchShallow, manualUpdate } = toRefs(props)

  // watch: {
  //   group(group) {
  //     chart.value.group = group
  //   },
  //   themeStore: {
  //     handler(data) {
  //       console.log(data)
  //     },
  //     deep: true,
  //     immediate: true,
  //   },
  // },

  onMounted(() => {
    initOptionsWatcher()
    INIT_TRIGGERS.forEach((prop) => {
      this.$watch(
        prop,
        () => {
          this.refresh()
        },
        { deep: true }
      )
    })
    REWATCH_TRIGGERS.forEach((prop) => {
      this.$watch(prop, () => {
        initOptionsWatcher()
        this.refresh()
      })
    })
    if (option.value) {
      echarts.registerTheme('vab-echarts-theme', theme)
      init()
    }
  })
  const activated = () => {
    if (autoResize.value) {
      chart.value && chart.value.resize()
    }
  }
  const destroyed = () => {
    if (chart.value) {
      this.destroy()
    }
  }
  const mergeOptions = (option, notMerge, lazyUpdate) => {
    if (manualUpdate.value) {
      manualOptions.value = option
    }
    if (!chart.value) {
      init(option)
    } else {
      delegateMethod('setOption', option, notMerge, lazyUpdate)
    }
  }
  const appendData = (params) => {
    delegateMethod('appendData', params)
  }
  const resize = (option) => {
    delegateMethod('resize', option)
  }
  const dispatchAction = (payload) => {
    delegateMethod('dispatchAction', payload)
  }
  const convertToPixel = (finder, value) => {
    return delegateMethod('convertToPixel', finder, value)
  }
  const convertFromPixel = (finder, value) => {
    return delegateMethod('convertFromPixel', finder, value)
  }
  const containPixel = (finder, value) => {
    return delegateMethod('containPixel', finder, value)
  }
  const showLoading = (type, option) => {
    delegateMethod('showLoading', type, option)
  }
  const hideLoading = () => {
    delegateMethod('hideLoading')
  }
  const getDataURL = (option) => {
    return delegateMethod('getDataURL', option)
  }
  const getConnectedDataURL = (option) => {
    return delegateMethod('getConnectedDataURL', option)
  }
  const clear = () => {
    delegateMethod('clear')
  }
  const dispose = () => {
    delegateMethod('dispose')
  }
  const delegateMethod = (name, ...args) => {
    if (!chart.value) {
      init()
    }
    return chart.value[name](...args)
  }
  const delegateGet = (methodName) => {
    if (!chart.value) {
      init()
    }
    return chart.value[methodName]()
  }
  const getArea = () => {
    return this.$el.offsetWidth * this.$el.offsetHeight
  }
  const init = (option) => {
    if (chart.value) {
      return
    }
    const newchart = echarts.init(this.$el, theme.value, initOptions.value)
    if (group.value) {
      newchart.group = group.value
    }
    newchart.setOption(option || manualOptions.value || option.value || {}, true)
    Object.keys(this.$attrs).forEach((event) => {
      const handler = this.$attrs[event]
      if (event.indexOf('zr:') === 0) {
        newchart.getZr().on(event.slice(3), handler)
      } else {
        newchart.on(event, handler)
      }
    })
    if (autoResize.value) {
      lastArea.value = getArea()
      this.__resizeHandler = debounce(
        () => {
          if (lastArea.value === 0) {
            this.mergeOptions({}, true)
            this.resize()
            this.mergeOptions(option.value || manualOptions.value || {}, true)
          } else {
            this.resize()
          }
          lastArea.value = getArea()
        },
        100,
        { leading: true }
      )
      addListener(this.$el, this.__resizeHandler)
    }
    Object.defineProperties(this, {
      width: {
        configurable: true,
        get: () => {
          return this.delegateGet('getWidth')
        },
      },
      height: {
        configurable: true,
        get: () => {
          return this.delegateGet('getHeight')
        },
      },
      isDisposed: {
        configurable: true,
        get: () => {
          return !!this.delegateGet('isDisposed')
        },
      },
      computedOptions: {
        configurable: true,
        get: () => {
          return this.delegateGet('getOption')
        },
      },
    })
    chart.value = chart
  }
  const initOptionsWatcher = () => {
    if (this.__unwatchOptions) {
      this.__unwatchOptions()
      this.__unwatchOptions = null
    }
    if (!manualUpdate.value) {
      this.__unwatchOptions = this.$watch(
        'option',
        (val, oldVal) => {
          if (!chart.value && val) {
            init()
          } else {
            chart.value.setOption(val, val !== oldVal)
          }
        },
        { deep: !this.watchShallow }
      )
    }
  }
  const destroy = () => {
    if (autoResize.value) {
      removeListener(this.$el, this.__resizeHandler)
    }
    this.dispose()
    chart.value = null
  }
  const refresh = () => {
    if (chart.value) {
      this.destroy()
      init()
    }
  }
  const connect = (group) => {
    if (typeof group !== 'string') {
      group = group.map((chart) => chart.chart)
    }
    echarts.connect(group)
  }
  const disconnect = (group) => {
    echarts.disConnect(group)
  }
  const getMap = (mapName) => {
    return echarts.getMap(mapName)
  }
  // graphic: echarts.graphic,
</script>
<style>
  .echarts {
    /* width: 600px; */
    height: 400px;
  }
</style>
