text: 'use strict';
  
  const Bottleneck = require('bottleneck')
    , lightsApi = require('./http/endpoints/lights')
    , ApiDefinition = require('./http/ApiDefinition.js')
    , ApiError = require('../ApiError')
    , util = require('../util')
    , Light = require('stream-lux-hue-bridge-model').model.Light
  ;
  
  /**
   * @typedef {import('stream-lux-hue-bridge-model').model.Light} Light
   * @typedef {import('stream-lux-hue-bridge-model').model.LightState} LightState
   * @type {Lights}
   */
  module.exports = class Lights extends ApiDefinition {
  
    constructor(hueApi) {
      super(hueApi);
  
      // As per Bridge documentation guidance, limit the number of calls to the light state changes to 10 per second max
      this._lightStateLimiter = new Bottleneck({maxConcurrent: 1, minTime: 60});
    }
  
    /**
     * Gets all the Lights from the Bridge
     * @returns {Promise<Light[]>}
     */
    getAll() {
      return this.execute(lightsApi.getAllLights);
    }
  
    /**
     * Get a specific Light from the Bridge.
     * @param id {number | Light} The id or Light instance to get from the Bridge.
     * @returns {Promise<Light>}
     */
    getLight(id) {
      const lightId = id.id || id;
  
      return this.getAll().then(lights => {
        const found = lights.filter(light => light.id === lightId);
  
        if (found.length === 0) {
          throw new ApiError(`Light ${lightId} not found`);
        }
        return found[0]
      });
    }
  
    /**
     * @deprecated since 4.0. Use getLight(id) instead.
     * @param id {number} The ide of the light to get.
     * @returns {Promise<Light>}
     */
    getLightById(id) {
      util.deprecatedFunction('5.x', 'lights.getLightById(id)', 'Use lights.getLight(id) instead.');
      return this.getLight(id);
    }
  
    /**
     * Retrieves a Light from the Bridge by name.
     * @param name {string} The name of the light to get.
     * @returns {Promise<Light[]>}
     */
    getLightByName(name) {
      return this.getAll().then(lights => {
        return lights.find(light => {
          return light.name === name;
        });
      });
    }
  
    /**
     * Discovers the "new" lights detected by the Bridge.
     * @returns {Promise<Light[]>}
     */
    getNew() {
      return this.execute(lightsApi.getNewLights);
    }
  
    /**
     * Starts a search for "new"/undiscovered Lights by the bridge. This can take up to 30 seconds to complete.
     * @returns {Promise<boolean>}
     */
    searchForNew() {
      return this.execute(lightsApi.searchForNewLights);
    }
  
    /**
     * Obtains the current Attributes and State settings for the specified Light.
     * @param id {number | Light} The id or Light instance to get the attributes and state for.
     * @returns {Promise<Object>}
     */
    getLightAttributesAndState(id) {
      return this.execute(lightsApi.getLightAttributesAndState, {id: id});
    }
  
    /**
     * Obtains the current State settings for the specified Light.
     * @param id {number | Light} The id or Light instance to get the current state for.
     * @returns {Promise<Object>}
     */
    getLightState(id) {
      return this.getLightAttributesAndState(id).then(result => { return result.state; });
    }
  
    /**
     * Sets the current state for the Light to desired settings.
     * @param id {number | Light} The id or Light instance to set the state on.
     * @param state {Object | LightState} The LightState to set on the light.
     * @returns {PromiseLike<any> | Promise<any>}
     */
    setLightState(id, state) {
      let lightId = id;
      if (id instanceof Light) {
        lightId = id.id;
      }
  
      return this.hueApi.getLightDefinition(lightId)
        .then(device => {
          if (!device) {
            throw new ApiError(`Light with id:${lightId} was not found on this bridge`);
          }
          return this._setLightState(id, state, device);
        });
    }
  
    /**
     * Renames a Light on the Bridge to the specified name in the Light instance.
     * @param light {Light} The Light to rename with the new name set.
     * @returns {Promise<boolean>}
     */
    renameLight(light) {
      if (light instanceof Light) {
        return this.execute(lightsApi.setLightAttributes, {id: light, light: light});
      } else {
        throw new ApiError('Light parameter is not an instance of a light');
      }
    }
  
    /**
     * @deprecated since 4.x, use renameLight(light) instead
     * @param id {int} The Light to rename.
     * @param name {string} The new name.
     * @returns {Promise}
     */
    rename(id, name) {
      if (arguments.length === 1) {
        util.deprecatedFunction('5.x', 'lights.rename(id, name)', 'Use lights.renameLight(light) instead.');
        return this.renameLight(id);
      } else {
        util.deprecatedFunction('5.x', 'lights.rename(id, name)', 'Use lights.renameLight(light) instead.');
        return this.execute(lightsApi.setLightAttributes, {id: id, name: name});
      }
    }
  
    /**
     * Deletes a Light from the Hue Bridge
     * @param id { number | Light} The id or Light instance to be deleted
     * @returns {Promise<boolean>}
     */
    deleteLight(id) {
      return this.execute(lightsApi.deleteLight, {id: id});
    }
  
    _setLightState(id, state, device) {
      const self = this;
  
      return this._lightStateLimiter.schedule(() => {
        return self.execute(lightsApi.setLightState, {id: id, state: state, device: device});
      });
    }
  };