import Utils from "@/Utils";

export default {
    mixins: [Utils],
    props: {
        /**
         * Component name
         */
        name: {
            type: String,
            default: '[Unnamed sensor]',
        },

        /**
         * Action (FontAwesome) icon class (default: `fa fa-play`)
         */
        iconClass: {
            type: String,
        },

        /**
         * Action icon URL (default: `fa fa-play`)
         */
        iconUrl: {
            type: String,
        },

        /**
         * Action icon color override, for FontAwesome icons
         */
        iconColor: {
            type: String,
        },

        /**
         * Actions to run upon interaction with the widget. Format:
         *
         * [
         *   {
         *     "action": "light.hue.toggle",
         *     "args": {
         *       "lights": ["Bulb 1", "Bulb 2"]
         *     }
         *   },
         *   {
         *     "action": "music.mpd.pause"
         *   }
         * ]
         */
        actions: {
            type: Array,
            default: () => { return [] },
        },

        /**
         * Map of variables used by this component, in the form
         * variable_name -> variable_value.
         */
        _vars: {
            type: Object,
            default: () => { return {} },
        },

        /**
         * Map of handlers, in the form of event_type -> functions.
         * Supported event handler types:
         *
         *   - mounted: Function to execute when the component is mounted.
         *   - beforeActions: Function to execute before the component action is run.
         *   - afterActions: Function to execute after the component action is run.
         *   - refresh: Function to be called at startup (if mounted is also specified
         *              then refresh will be called after mounted when the component is
         *              first mounted) and at regular intervals defined on the
         *              interval property (default: 10 seconds).
         *   - events: This is a mapping of functions that react to Platypush
         *             platform events published on the websocket (e.g. lights or
         *             switches toggles, media events etc.). The form is
         *             platypush_event_type -> function.
         */
        handlers: {
            type: Object,
            default: () => { return {} },
        },

        /**
         * Event bus
         */
        bus: {
            type: Object,
        },
    },

    data() {
        return {
            vars: {...(this._vars || {})},
            _interval: undefined,
            refresh: null,
            refreshInterval: null,
            value: null,
            loading: false,
        }
    },

    computed: {
        iconStyle() {
            if (!this.iconClass?.length && this.iconColor?.length)
                return

            return {'color': this.iconColor}
        },

        hasIcon() {
            return this.iconUrl?.length || this.iconClass?.length
        },
    },

    methods: {
        async run() {
            if (this.handlers.input)
                return this.handlers.input(this)(this.value)

            if (this.handlers.beforeActions)
                await this.handlers.beforeActions(this)
            for (const action of this.actions)
                await this.request_(action)
            if (this.handlers.afterActions) {
                await this.handlers.afterActions(this)
            }
        },

        async request_(action) {
            const args = Object.entries(action.args).reduce((args, [key, value]) => {
                if (value.trim) {
                    value = value.trim()
                    const m = value.match(/^{{\s*(.*)\s*}}/)
                    if (m) {
                        value = eval(`// noinspection JSUnusedLocalSymbols
                        (function (self) {
                            return ${m[1]}
                        })`)(this)
                    }
                }

                args[key] = value
                return args
            }, {})

            await this.request(action.action, args)
        },

        async processEvent(event) {
            const hndl = (this.handlers.events || {})[event.type]
            if (hndl)
                await hndl(this)(event)
        },
    },

    async mounted() {
        this.$root.bus.on('event', this.processEvent)

        if (this.handlers.mounted)
            await this.handlers.mounted(this)

        if (this.handlers.refresh) {
            this.refreshInterval = (this.handlers.refresh?.interval || 0) * 1000
            this.refresh = () => {
                this.handlers.refresh.handler(this)
            }

            await this.refresh()
            if (this.refreshInterval) {
                const self = this
                const wrapper = () => { return self.refresh() }
                this._interval = setInterval(wrapper, this.refreshInterval)
            }
        }
    },

    unmounted() {
        if (this._interval)
            clearInterval(this._interval)
    }
}
