import { defineComponent, h, onMounted, nextTick, ref, PropType, Ref } from 'vue'
import { CSpinner } from '../spinner'

const CElementCover = defineComponent({
  name: 'CElementCover',
  props: {
    /**
     * Array of custom boundaries. Use to create custom cover area (instead of parent element area). Area is defined by four sides: 'top', 'bottom', 'right', 'left'. If side is not defined by any custom boundary it is equal to parent element boundary. Each custom boundary is object with keys:
     * - sides (array) - select boundaries of element to define boundaries. Sides names: 'top', 'bottom', 'right', 'left'.
     * - query (string) - query used to get element which define boundaries. Search will be done only inside parent element, by parent.querySelector(query) function. [docs]
     *
     * @type {sides: string[], query: string}[]
     */
    boundaries: Array as PropType<{ sides: string[]; query: string }[]>,
    /**
     * Opacity of the cover. [docs]
     *
     * @type number
     */
    opacity: {
      type: Number,
      default: 0.4,
    },
  },
  /**
   * Location for custom content.
   *
   * @slot default
   */
  setup(props, { slots }) {
    const elementCoverRef = ref() as Ref<HTMLElement>
    const customBoundaries = ref({})

    const getCustomBoundaries = () => {
      if (!props.boundaries || elementCoverRef === null) {
        return {}
      }

      const parent = elementCoverRef.value.parentElement
      if (!parent) {
        return {}
      }

      const parentCoords: {[key: string]: any} = parent.getBoundingClientRect()
      const customBoundaries: {[key: string]: string} = {}
      props.boundaries.forEach(({ sides, query }) => {
        const element = parent.querySelector(query)
        if (!element || !sides) {
          return
        }

        const coords: {[key: string]: any} = element.getBoundingClientRect()
        sides.forEach((side) => {
          const sideMargin = Math.abs(coords[side] - parentCoords[side])
          customBoundaries[side] = `${sideMargin}px`
        })
      })
      return customBoundaries
    }

    const containerCoords = {
      top: 0,
      left: 0,
      right: 0,
      bottom: 0,
    }

    const coverStyles = {
      ...containerCoords,
      position: 'absolute',
      'z-index': 2,
      'background-color': `rgba(255,255,255,${props.opacity})`,
    }

    onMounted(() => {
      nextTick(() => {
        customBoundaries.value = getCustomBoundaries()
      })
    })

    return () =>
      h(
        'div',
        {
          style: { ...coverStyles, ...customBoundaries.value },
          ref: elementCoverRef,
        },
        h(
          'div',
          {
            style: {
              position: 'absolute',
              top: '50%',
              left: '50%',
              transform: 'translateX(-50%) translateY(-50%)',
            },
          },
          slots.default
            ? slots.default()
            : h(CSpinner, {
                variant: 'grow',
                color: 'primary',
              }),
        ),
      )
  },
})

export { CElementCover }
