<template>
  <div>
    <b-container fluid :class="containerClass">
      <b-row>
        <b-col class="mb-2 col-12">
          <span :class="titleClass">{{ title }}</span>
        </b-col>
        <b-col class="mb-2 col-12">
          {{ subTitle }}
        </b-col>
      </b-row>

      <b-row>
        <b-col sm="12">
          <component :is="typeComponents.get(type)['wrapComponent']">
            <div :class="layoutListClasses" v-for="(item, index) in options" :key="`option-message-${index}`">
              <component
                :is="typeComponents.get(type)['listComponent']"
                v-model="optionsData[indexFn(type, index)]"
                :name="nameFn(type, index)"
                :value="optionValue(item, index)"
                :class="{ 'initializing-light-extra': loading }"
                class="mt-1 d-inline-block"
                :key="`option-message-${index}`"
                :data-qa="`option-message-${index + 1}`"
              >
                <span class="text-dark option-hyperlink" v-html="optionText(item, index)" />
              </component>
            </div>
          </component>
        </b-col>
      </b-row>
    </b-container>
  </div>
</template>
<script>
import _ from 'lodash'

export default {
  props: {
    title: {
      type: String,
      default: '',
    },
    subTitle: {
      type: String,
      default: '',
    },
    options: {
      type: Array,
      default: () => [],
    },
    containerClass: {
      type: [Array, String],
      default: '',
    },
    titleClass: {
      type: [Array, String],
      default: 'font-weight-bold',
    },
    type: {
      type: String,
      default: 'check',
    },
    value: {
      type: [Number, Array, String],
      default: null,
    },
    layout: {
      type: String,
      default: 'vertical',
    },
    loading: {
      type: Boolean,
      default: false,
    },
    typeComponents: {
      type: Map,
      default: () =>
        new Map([
          [
            'check',
            {
              listComponent: 'b-check',
              wrapComponent: 'div',
              nameFn(type, index) {
                return `${type}-${index}`
              },
              indexFn(type, index) {
                return index
              },
              valueFn(value) {
                let defaultValues = new Array(this.options.length).fill(false)

                return _.merge(defaultValues, value)
              },
            },
          ],
          [
            'radio',
            {
              listComponent: 'b-form-radio',
              wrapComponent: 'b-form-group',
              data: 'wrapperData',
              nameFn(type, index) {
                return `${type}`
              },
              indexFn(type, index) {
                return 0
              },
              valueFn(value) {
                return value[0]
              },
            },
          ],
        ]),
    },
  },
  data: () => ({
    optionsData: [],
  }),
  methods: {
    typedFn(fn) {
      return this.typeComponents.get(this.type)[fn].bind(this)
    },
    nameFn(type, index) {
      return this.typedFn('nameFn')(type, index)
    },
    indexFn(type, index) {
      return this.typedFn('indexFn')(type, index)
    },
    optionValue(item, index) {
      if (Array.isArray(item)) {
        return item[0]
      } else if (typeof item === 'object' && item.value !== undefined) {
        return item.value
      } else {
        return index
      }
    },
    optionText(item, index) {
      if (Array.isArray(item)) {
        return item[1]
      } else if (typeof item === 'object' && item.value !== undefined) {
        return item.text
      } else {
        return item
      }
    },
  },
  computed: {
    layoutListClasses() {
      return (this.layout === 'vertical' && []) || (this.layout === 'horizontal' && ['d-inline-block', 'mr-3']) || []
    },
  },
  watch: {
    optionsData: {
      handler: function(val, oldVal) {
        let value = this.typedFn('valueFn')(val)

        if (value !== undefined && value !== null) {
          this.$emit('input', this.typedFn('valueFn')(val))
        }
      },
      immediate: true,
    },
    value: {
      handler: function(val, oldValue) {
        if (Array.isArray(val)) {
          if (val != this.optionsData) {
            val.forEach((item, index) => {
              let itemIndex = this.indexFn(this.type, index)

              this.optionsData[itemIndex] = _.clone(item)
            })
          }
        } else {
          if (this.optionsData[this.indexFn(this.type, 0)] != val) {
            this.optionsData[this.indexFn(this.type, 0)] = _.clone(val)
          }
        }
      },
      immediate: true,
    },
  },
}
</script>
