<template>
  <div>
    <div class="u-mb2" v-if="pluginSlot">
      <component
        :is="contentComponent"
        ref="pluginContent"
        :context="context"
      />
    </div>
  </div>
</template>

<script>
import { PluginSlotMixin } from './mixins.js'

export default {
  name: 'PluginMarkup',
  mixins: [PluginSlotMixin],
  data () {
    return {
      pluginOptions: {},
      contentComponent: { template: '<div></div>' }
    }
  },
  methods: {
    getSlotExposedMethods () {
      return {
        getData: this.getData,
        setData: this.setData,
        initializeVendorIframe: this.initializeVendorIframe,
        makeRequest: this.makeRequest,
        showLoadingIndicator: this.showLoadingIndicator
      }
    },
    setData (data) {
      for (const key in data) {
        this.$set(this.$refs.pluginContent, key, data[key])
      }
    },
    getData (key) {
      return this.$refs.pluginContent[key]
    },
    async mapLocalMethodsToIframeMethods (methodsList) {
      const methods = {}
      const iframe = await this.pluginIframeConnection.promise
      for (const method of methodsList) {
        const mappedMethod = async (...args) => {
          let cb = result => result
          // extract callbacks if any, because Penpal doesn't allow transfer of non serializeable objects
          // and callbacks should get called in the context of the UI not the context of plugin Iframe.
          args = args.filter(arg => {
            if (typeof arg !== 'function') return true
            cb = arg
            return false
          })
          const result = await iframe[method](...args)
          return cb(result)
        }
        methods[method] = mappedMethod
      }
      return methods
    },
    registerPluginContentComponent ({ data, template, methods }) {
      this.contentComponent = {
        template,
        props: {
          context: {
            type: Object,
            default: () => ({})
          }
        },
        data () {
          return data
        },
        methods
      }
    },
    sanitizeTemplate (templateString) {
      const regex = /\$\w+\.?/g
      const sanitizedTemplate = templateString
        .replace(regex, '')
        .replace('{{}}', '')
      return sanitizedTemplate
    },
    async initializeSlot (options) {
      this.handleResponseName = options.handleResponse
      this.handleErrorName = options.handleError
      const methods = await this.mapLocalMethodsToIframeMethods(options.methods)
      const template = this.sanitizeTemplate(options.template)
      this.registerPluginContentComponent({
        data: options.data,
        template,
        methods
      })
    }
  }
}
</script>
