<template>
  <Loading v-if="loading" />
  <LightPlugin plugin-name="light.hue" :config="config" :lights="lights" :groups="groups" :scenes="scenes"
               :animations="animations" :initial-group="initialGroup" :loading-groups="loadingGroups"
               :color-converter="colorConverter" @group-toggle="toggleGroup" @light-changed="onLightChanged"
               @light-toggle="toggleLight" @set-light="setLight" @set-group="setGroup" @select-scene="setScene"
               @start-animation="startAnimation" @stop-animation="stopAnimation" @refresh="refresh(true)"/>
</template>

<script>
import LightPlugin from "@/components/panels/Light/Index";
import LightUtils from "@/components/panels/Light/Utils";
import { ColorConverter } from "@/components/panels/Light/color"
import Utils from "@/Utils";
import Loading from "@/components/Loading";

export default {
  name: "LightHue",
  components: {Loading, LightPlugin},
  mixins: [Utils, LightUtils],
  props: {
    config: {
      type: Object,
      default: () => {},
    },
  },

  data() {
    return {
      loading: false,
      colorConverter: new ColorConverter({
        hue: [0, 65535],
        sat: [0, 255],
        bri: [0, 255],
        ct: [150, 500],
      })
    }
  },

  computed: {
    initialGroup() {
      if (!this.config.groups || !Object.keys(this.config.groups).length)
        return null

      const group = this.config.groups[0]
      if (group in this.groups)
        return this.groups[group].id
      else if (group in this.groupsByName)
        return this.groupsByName[group].id
      return null
    },
  },

  methods: {
    async getLights() {
      return await this.request('light.hue.get_lights')
    },

    async getGroups() {
      return Object.entries(await this.request('light.hue.get_groups'))
          .filter((group) => !group[1].recycle && group[1].type.toLowerCase() === 'room')
          .reduce((obj, [id, group]) => {
            obj[id] = group
            return obj
          }, {})
    },

    async getScenes() {
      return Object.entries(await this.request('light.hue.get_scenes'))
          .filter((scene) =>
            !scene[1].recycle &&
            ['lightscene', 'groupscene'].includes(scene[1].type.toLowerCase())
          )
          .reduce((obj, [id, scene]) => {
            obj[id] = scene
            return obj
          }, {})
    },

    async getAnimations() {
      return await this.request('light.hue.get_animations')
    },

    async toggleGroup(group) {
      let groups = Object.values(this.groups)
      let args = {
        groups: groups.map((group) => group.name)
      }

      if (group != null) {
        groups = [group]
        args = {
          groups: [group.name],
        }
      }

      await this.groupAction('light.hue.toggle',  args, ...groups)
      await this.refresh(true)
    },

    async toggleLight(light) {
      const lights = [light]
      const args = light != null ? {
        lights: [light.name],
      } : {}

      await this.lightAction('light.hue.toggle',  args, ...lights)
      await this.refresh(true)
    },

    async setLight(event) {
      let lights = Object.keys(this.lights)
      const light = event.light
      const args = {}

      if (light) {
        args.lights = [light.name]
        lights = [light]
      }

      const self = this
      const requests = Object.entries(event.value).map(([attr, value]) => {
        let method = null;
        args.value = value

        switch (attr) {
          case 'brightness':
            method = 'light.hue.bri'
            break

          case 'temperature':
            method = 'light.hue.ct'
            break

          case 'xy':
            method = 'light.hue.xy'
            break
        }

        if (method)
          return self.lightAction(method, args, ...lights)
      }).filter((req) => req != null)

      await Promise.all(requests)
      await this.refresh(true)
    },

    async setGroup(event) {
      if (!event.groupId)
        return this.setLight(event)

      const group = this.groups[event.groupId]
      const args = {
        groups: [group.name],
      }

      const self = this
      const requests = Object.entries(event.value).map(([attr, value]) => {
        let method = null;
        args.value = value

        switch (attr) {
          case 'brightness':
            method = 'light.hue.bri'
            break

          case 'temperature':
            method = 'light.hue.ct'
            break

          case 'xy':
            method = 'light.hue.xy'
            break
        }

        if (method)
          return self.groupAction(method, args, group)
      }).filter((req) => req != null)

      await Promise.all(requests)
      await this.refresh(true)
    },

    async setScene(event) {
      await this.groupAction('light.hue.scene',  {
        name: this.scenes[event.sceneId].name,
        groups: [this.groups[event.groupId].name],
      }, this.groups[event.groupId])

      await this.refresh(true)
    },

    async refresh(background) {
      if (!background)
        this.loading = true

      try {
        [this.lights, this.groups, this.scenes, this.animations] = await Promise.all([
          this.getLights(),
          this.getGroups(),
          this.getScenes(),
          this.getAnimations(),
        ])
      } finally {
        if (!background)
          this.loading = false
      }
    },

    async startAnimation(event) {
      await this.request('light.hue.animate', {
        lights: event.lights,
        ...event.animation,
      })

      await this.refresh(true)
    },

    async stopAnimation() {
      await this.request('light.hue.stop_animation')
      await this.refresh(true)
    },

    onLightChanged(event) {
      this.lights[event.id].state = {
        ...this.lights[event.id].state,
        ...event.state,
      }
    },
  },

  mounted() {
    this.refresh()
  },
}
</script>

<style lang="scss" scoped>
.lights-plugin {
  @include until($tablet) {
    padding: 0.5em;
  }
}
</style>
