<template>
  <div
    v-if="elementMode === 'editing' || isVisible"
    class="element__wrapper"
    :class="{
      'element__wrapper--full-bleed':
        element.style_width === WIDTH_TYPES.FULL.value,
      'element__wrapper--full-width':
        element.style_width === WIDTH_TYPES.FULL_WIDTH.value,
      'element__wrapper--medium-width':
        element.style_width === WIDTH_TYPES.MEDIUM.value,
      'element__wrapper--small-width':
        element.style_width === WIDTH_TYPES.SMALL.value,
    }"
    :style="elementStyles"
  >
    <div class="element__inner-wrapper">
      <component
        :is="component"
        :element="element"
        :children="children"
        :application-context-additions="{
          element,
        }"
        class="element"
      />
    </div>
  </div>
</template>

<script>
import { resolveColor } from '@baserow/modules/core/utils/colors'
import { themeToColorVariables } from '@baserow/modules/builder/utils/theme'

import {
  BACKGROUND_TYPES,
  WIDTH_TYPES,
  BACKGROUND_MODES,
} from '@baserow/modules/builder/enums'
import applicationContextMixin from '@baserow/modules/builder/mixins/applicationContext'
import {
  VISIBILITY_NOT_LOGGED,
  VISIBILITY_LOGGED_IN,
  ROLE_TYPE_ALLOW_EXCEPT,
  ROLE_TYPE_DISALLOW_EXCEPT,
} from '@baserow/modules/builder/constants'
import { mapGetters } from 'vuex'

export default {
  name: 'PageElement',
  mixins: [applicationContextMixin],
  inject: ['builder', 'page', 'mode'],
  provide() {
    return { mode: this.elementMode }
  },
  props: {
    element: {
      type: Object,
      required: true,
    },
    forceMode: {
      type: String,
      required: false,
      default: null,
    },
  },
  computed: {
    BACKGROUND_TYPES: () => BACKGROUND_TYPES,
    WIDTH_TYPES: () => WIDTH_TYPES,
    colorVariables() {
      return themeToColorVariables(this.builder.theme)
    },
    elementMode() {
      return this.forceMode !== null ? this.forceMode : this.mode
    },
    component() {
      const elementType = this.$registry.get('element', this.element.type)
      const componentName =
        this.elementMode === 'editing' ? 'editComponent' : 'component'
      return elementType[componentName]
    },
    children() {
      return this.$store.getters['element/getChildren'](this.page, this.element)
    },
    ...mapGetters({
      loggedUser: 'userSourceUser/getUser',
    }),
    isVisible() {
      const isAuthenticated = this.$store.getters[
        'userSourceUser/isAuthenticated'
      ](this.builder)
      const user = this.loggedUser(this.builder)
      const roles = this.element.roles
      const roleType = this.element.role_type

      const visibility = this.element.visibility
      if (visibility === VISIBILITY_LOGGED_IN) {
        if (!isAuthenticated) {
          return false
        }

        if (roleType === ROLE_TYPE_ALLOW_EXCEPT) {
          return !roles.includes(user.role)
        } else if (roleType === ROLE_TYPE_DISALLOW_EXCEPT) {
          return roles.includes(user.role)
        } else {
          return true
        }
      } else if (visibility === VISIBILITY_NOT_LOGGED) {
        return !isAuthenticated
      } else {
        return true
      }
    },
    elementStyles() {
      const styles = {
        '--element-background-color':
          this.element.style_background === BACKGROUND_TYPES.COLOR
            ? this.resolveColor(
                this.element.style_background_color,
                this.colorVariables
              )
            : 'none',

        '--element-background-image':
          this.element.style_background_file !== null
            ? `url(${this.element.style_background_file.url})`
            : 'none',

        '--element-border-top': this.border(
          this.element.style_border_top_size,
          this.element.style_border_top_color
        ),
        '--element-margin-top': `${this.element.style_margin_top || 0}px`,
        '--element-padding-top': `${this.element.style_padding_top || 0}px`,
        '--element-border-bottom': this.border(
          this.element.style_border_bottom_size,
          this.element.style_border_bottom_color
        ),
        '--element-margin-bottom': `${this.element.style_margin_bottom || 0}px`,
        '--element-padding-bottom': `${
          this.element.style_padding_bottom || 0
        }px`,
        '--element-border-left': this.border(
          this.element.style_border_left_size,
          this.element.style_border_left_color
        ),
        '--element-margin-left': `${this.element.style_margin_left || 0}px`,
        '--element-padding-left': `${this.element.style_padding_left || 0}px`,
        '--element-border-right': this.border(
          this.element.style_border_right_size,
          this.element.style_border_right_color
        ),
        '--element-margin-right': `${this.element.style_margin_right || 0}px`,

        '--element-padding-right': `${this.element.style_padding_right || 0}px`,
      }

      if (this.element.style_background_file !== null) {
        if (this.element.style_background_mode === BACKGROUND_MODES.FILL) {
          styles['--element-background-size'] = 'cover'
          styles['--element-background-repeat'] = 'no-repeat'
        }
        if (this.element.style_background_mode === BACKGROUND_MODES.TILE) {
          styles['--element-background-size'] = 'auto'
          styles['--element-background-repeat'] = 'repeat'
        }
        if (this.element.style_background_mode === BACKGROUND_MODES.FIT) {
          styles['--element-background-size'] = 'contain'
          styles['--element-background-repeat'] = 'no-repeat'
        }
      }

      return styles
    },
  },
  methods: {
    resolveColor,
    border(size, color) {
      if (!size) {
        return 'none'
      }
      return `solid ${size}px ${this.resolveColor(color, this.colorVariables)}`
    },
  },
}
</script>