import { Service, PlatformAccessory, CharacteristicValue, CharacteristicSetCallback, Characteristic } from 'homebridge';
import { TasmotaService } from './TasmotaService';
import { tasmotaPlatform } from './platform';

import createDebug from 'debug';
const debug = createDebug('Tasmota:fan');

/**
 * Platform Accessory
 * An instance of this class is created for each accessory your platform registers
 * Each accessory may expose multiple services of different service types.
 */

export class tasmotaFanService extends TasmotaService {

  constructor(
    public readonly platform: tasmotaPlatform,
    public readonly accessory: PlatformAccessory,
    protected readonly uniq_id: string,
  ) {

    super(platform, accessory, uniq_id);

    this.service = this.accessory.getService(this.uuid) || this.accessory.addService(this.platform.Service.Fan,
      accessory.context.device[this.uniq_id].name, this.uuid);

    if (!this.service.displayName) {
      this.service.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device[this.uniq_id].name);
    }

    if (this.service.getCharacteristic(this.platform.Characteristic.On).listenerCount('set') < 1) {
      this.characteristic = this.service.getCharacteristic(this.platform.Characteristic.On)
        .on('set', this.setOn.bind(this));
      this.enableStatus();
    }

    // Does the Fan include a RotationSpeed characteristic

    if (accessory.context.device[this.uniq_id].bri_cmd_t) {
      (this.service.getCharacteristic(this.platform.Characteristic.RotationSpeed) ||
        this.service.addCharacteristic(this.platform.Characteristic.RotationSpeed))
        .on('set', this.setRotationSpeed.bind(this));
    } else if (accessory.context.device[this.uniq_id].spds) {
      (this.service.getCharacteristic(this.platform.Characteristic.RotationSpeed) ||
        this.service.addCharacteristic(this.platform.Characteristic.RotationSpeed))
        .on('set', this.setRotationSpeedFixed.bind(this));
      //        .setProps({     // This causes an issue with validateUserInput in Characteristic and 33.3333 becomes 0
      //          minStep: 33.33333333333333,
      //        });
    }

  }


  /**
   * Handle "STATE" messages from Tasmotastat_t:
   * These are sent when the device's state is changed, either via HomeKit, Local Control or Other control methods.
   */

  statusUpdate(topic, message) {
    debug('statusUpdate', topic, message.toString());

    this.accessory.context.timeout = this.platform.autoCleanup(this.accessory);

    try {
      let value = message.toString();

      if (this.accessory.context.device[this.uniq_id].val_tpl) {
        value = this.parseValue(this.accessory.context.device[this.uniq_id].val_tpl, message.toString());
      }

      if (this.service.getCharacteristic(this.platform.Characteristic.On).value !== (value ===
        this.accessory.context.device[this.uniq_id].pl_on ? true : false)) {

        // Use debug logging for no change updates, and info when a change occurred

        this.platform.log.info('Updating \'%s\' to %s', this.service.displayName, value);

      } else {
        this.platform.log.debug('Updating \'%s\' to %s', this.service.displayName, value);
      }
      this.platform.log.debug('Updating \'%s\' to %s ? %s', this.service.displayName, value, this.accessory.context.device[this.uniq_id].pl_on);
      this.platform.log.debug('Updating \'%s\' to %s ? %s', this.service.displayName, value, (value ===
        this.accessory.context.device[this.uniq_id].pl_on ? true : false));
      this.service.getCharacteristic(this.platform.Characteristic.On).updateValue((value ===
        this.accessory.context.device[this.uniq_id].pl_on ? true : false));

      // Update RotationSpeed if supported

      if (this.accessory.context.device[this.uniq_id].bri_val_tpl) {

        // Use debug logging for no change updates, and info when a change occurred
        const bri_val = this.parseValue(this.accessory.context.device[this.uniq_id].bri_val_tpl, message.toString());

        if (this.service.getCharacteristic(this.platform.Characteristic.RotationSpeed).value != bri_val) {
          this.platform.log.info('Updating \'%s\' RotationSpeed to %s', this.service.displayName, bri_val);
        } else {
          this.platform.log.debug('Updating \'%s\' RotationSpeed to %s', this.service.displayName, bri_val);
        }
        this.service.getCharacteristic(this.platform.Characteristic.RotationSpeed).updateValue(bri_val);
      }
    } catch (err) {
      this.platform.log.error('ERROR: Message Parse Error', topic, message.toString());
    }
  }

  setOn(value: CharacteristicValue, callback: CharacteristicSetCallback) {
    this.platform.log.info('%s Set Characteristic On ->', this.accessory.displayName, value);

    if (!this.accessory.context.device[this.uniq_id].spds) {
      // Not hampton bay fans with speeds rather than on
      this.accessory.context.mqttHost.sendMessage(this.accessory.context.device[this.uniq_id].cmd_t, (value ?
        this.accessory.context.device[this.uniq_id].pl_on : this.accessory.context.device[this.uniq_id].pl_off));
    } else if (!value) {
      // Turning off
      this.accessory.context.mqttHost.sendMessage(this.accessory.context.device[this.uniq_id].cmd_t, (value ?
        this.accessory.context.device[this.uniq_id].pl_on : this.accessory.context.device[this.uniq_id].pl_off));
    } else {
      // Turning on of Hampton bay RF Fans, they don't have a ON function but can restore previous speed
      this.setRotationSpeedFixed(this.service.getCharacteristic(this.platform.Characteristic.RotationSpeed).value || 25, callback);
      return;
    }
    callback(null);
  }

  setRotationSpeed(value: CharacteristicValue, callback: CharacteristicSetCallback) {
    this.platform.log.info('%s Set Characteristic RotationSpeed ->', this.accessory.displayName, value);
    this.accessory.context.mqttHost.sendMessage(this.accessory.context.device[this.uniq_id].bri_cmd_t, value.toString());
    callback(null);
  }

  setRotationSpeedFixed(value: CharacteristicValue, callback: CharacteristicSetCallback) {
    // debug('config', this.accessory.displayName, this.accessory.context.device[this.uniq_id]);
    this.platform.log.info('%s Set Characteristic RotationSpeedFixed ->', this.accessory.displayName, value);
    if (value < 25) { // off
      this.accessory.context.mqttHost.sendMessage(this.accessory.context.device[this.uniq_id].cmd_t, this.accessory.context.device[this.uniq_id].pl_off);
    } else if (value < 50) {  // low
      // debug('low', this.accessory.displayName, this.accessory.context.device[this.uniq_id].pl_lo_spd);
      this.accessory.context.mqttHost.sendMessage(this.accessory.context.device[this.uniq_id].cmd_t, this.accessory.context.device[this.uniq_id].pl_lo_spd);
    } else if (value < 75) {  // medium
      // debug('medium', this.accessory.displayName, this.accessory.context.device[this.uniq_id].pl_med_spd);
      this.accessory.context.mqttHost.sendMessage(this.accessory.context.device[this.uniq_id].cmd_t, this.accessory.context.device[this.uniq_id].pl_med_spd);
    } else {  // high
      // debug('high', this.accessory.displayName, this.accessory.context.device[this.uniq_id].pl_hi_spd);
      this.accessory.context.mqttHost.sendMessage(this.accessory.context.device[this.uniq_id].cmd_t, this.accessory.context.device[this.uniq_id].pl_hi_spd);

    }
    callback(null);
  }
}