const base = ['borderRadius', 'borderColor', 'borderWidth', 'backgroundColor']
const text = ['paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', 'color', 'textAlign', 'lineHeight', 'fontSize', 'fontWeight', 'textOverflow', 'whiteSpace']
const image = []
const textAlign = { start: 'left', end: 'right' }
let index = 0

export default {
  name: 'Cover',
  data () {
    return {
      style: {}
    }
  },
  computed: {
    viewPosition () {
      const position = {}
      for (const key in this.position) {
        let val = this.position[key]
        const valNumber = parseFloat(val)
        const parentValNumber = parseFloat(this._nativeParent.position[key])
        if (key === 'top' || key === 'left') {
          val = Math.max(valNumber, parentValNumber) + 'px'
        } else if (key === 'width' || key === 'height') {
          const base = key === 'width' ? 'left' : 'top'
          const parentStart = parseFloat(this._nativeParent.position[base])
          const viewStart = parseFloat(this.position[base])
          const diff1 = Math.max(parentStart - viewStart, 0)
          const diff2 = Math.max((viewStart + valNumber) - (parentStart + parentValNumber), 0)
          val = Math.max(valNumber - diff1 - diff2, 0) + 'px'
        }
        position[key] = val
      }
      return position
    },
    tags () {
      const position = this._getTagPosition()
      const style = this.style
      const tags = [{
        tag: 'rect',
        position,
        rectStyles: {
          color: style.backgroundColor,
          radius: style.borderRadius,
          borderColor: style.borderColor,
          borderWidth: style.borderWidth
        }
      }]
      if (this.coverType === 'image') {
        tags.push({
          tag: 'img',
          position,
          src: this.coverContent
        })
      } else {
        const lineSpacing = parseFloat(style.lineHeight) - parseFloat(style.fontSize)
        let width = parseFloat(position.width) - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight)
        width = width < 0 ? 0 : width
        let height = parseFloat(position.height) - parseFloat(style.paddingTop) - lineSpacing / 2 - parseFloat(style.paddingBottom)
        height = height < 0 ? 0 : height
        tags.push({
          tag: 'font',
          position: {
            top: `${parseFloat(position.top) + parseFloat(style.paddingTop) + lineSpacing / 2}px`,
            left: `${parseFloat(position.left) + parseFloat(style.paddingLeft)}px`,
            width: `${width}px`,
            height: `${height}px`
          },
          textStyles: {
            align: textAlign[style.textAlign] || style.textAlign,
            color: style.color,
            decoration: 'none',
            lineSpacing: `${lineSpacing}px`,
            margin: '0px',
            overflow: style.textOverflow,
            size: style.fontSize,
            verticalAlign: 'top',
            weight: style.fontWeight,
            whiteSpace: style.whiteSpace
          },
          text: this.coverContent
        })
      }
      return tags
    }
  },
  created () {
    let $parent = this.$parent
    while (!$parent.isNative && $parent !== this.$root) {
      $parent = $parent.$parent
    }
    this._nativeParent = $parent
  },
  mounted () {
    this._updateStyle()
    const $nativeParent = this._nativeParent
    if ($nativeParent.isNative) {
      if ($nativeParent._isMounted) {
        this._onCanInsert()
      } else {
        $nativeParent.onCanInsertCallbacks.push(() => {
          this._onCanInsert()
        })
      }
      this.$watch('hidden', (val) => {
        this.cover && this.cover[val ? 'hide' : 'show']()
      })
      this.$watch('viewPosition', (val) => {
        this.cover && this.cover.setStyle(val)
      }, { deep: true })
      this.$watch('tags', () => {
        const cover = this.cover
        if (cover) {
          cover.reset()
          cover.draw(this.tags)
        }
      }, { deep: true })
      this.$on('uni-view-update', this._requestStyleUpdate)
    }
  },
  beforeDestroy () {
    if (this._nativeParent.isNative) {
      this.cover && this.cover.close()
      delete this.cover
    }
  },
  methods: {
    _onCanInsert () {
      const cover = this.cover = new plus.nativeObj.View(`cover-${Date.now()}-${index++}`, this.viewPosition, this.tags)
      plus.webview.currentWebview().append(cover)
      if (this.hidden) {
        cover.hide()
      }
      cover.addEventListener('click', () => {
        this.$trigger('click', {}, {})
      })
    },
    _getTagPosition () {
      const position = {}
      for (const key in this.position) {
        let val = this.position[key]
        if (key === 'top' || key === 'left') {
          val = Math.min((parseFloat(val) - parseFloat(this._nativeParent.position[key])), 0) + 'px'
        }
        position[key] = val
      }
      return position
    },
    _updateStyle () {
      const style = getComputedStyle(this.$el)
      base.concat(text, image).forEach(key => {
        this.style[key] = style[key]
      })
    },
    _requestStyleUpdate () {
      if (this._styleUpdateRequest) {
        cancelAnimationFrame(this._styleUpdateRequest)
      }
      this._styleUpdateRequest = requestAnimationFrame(() => {
        delete this._styleUpdateRequest
        this._updateStyle()
      })
    }
  }
}
