import { pond } from "protobuf-ts/pond";
import { quack } from "protobuf-ts/pond";
import { or } from "utils/types";
import { cloneDeep } from "lodash";
import { Component } from "models";
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";

export class Ambient {
  public settings: pond.ComponentSettings = pond.ComponentSettings.create();
  public status: pond.ComponentStatus = pond.ComponentStatus.create();
  public temperature: number = -127;
  public humidity: number = 200;

  public static create(comp: Component): Ambient {
    let my = new Ambient();
    my.settings = comp.settings;
    my.status = comp.status;

    if (comp.status.measurement.length > 0) {
      comp.status.measurement.forEach(um => {
        if (um.values[0]) {
          if (um.type === quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE) {
            my.temperature = or(um.values[0].values[0], -127);
          }
          if (um.type === quack.MeasurementType.MEASUREMENT_TYPE_PERCENT) {
            my.humidity = or(um.values[0].values[0], 200);
          }
        }
      });
    } else {
      let temp = comp.status?.lastMeasurement?.measurement?.humidityAndTemperature?.celciusTimes_10;
      let hum =
        comp.status?.lastMeasurement?.measurement?.humidityAndTemperature
          ?.relativeHumidityTimes_100;
      if (temp === undefined) {
        if (comp.status?.lastMeasurement?.measurement?.humidityAndTemperature) {
          let humAndTemp = comp.status?.lastMeasurement?.measurement?.humidityAndTemperature as any;
          temp = humAndTemp["celciusTimes10"];
          hum = humAndTemp["relativeHumidityTimes100"];
        }
      }
      my.temperature = or(temp, -1270) / 10;
      my.humidity = or(hum, 20000) / 100;
    }

    return my;
  }

  public static createPond(comp: pond.Component): Ambient {
    let my = new Ambient();
    my.settings = comp.settings ? comp.settings : pond.ComponentSettings.create();
    my.status = comp.status ? comp.status : pond.ComponentStatus.create();
    let temp = comp.status?.lastMeasurement?.measurement?.humidityAndTemperature?.celciusTimes_10;
    let hum =
      comp.status?.lastMeasurement?.measurement?.humidityAndTemperature?.relativeHumidityTimes_100;
    if (temp === undefined) {
      if (comp.status?.lastMeasurement?.measurement?.humidityAndTemperature) {
        let humAndTemp = comp.status?.lastMeasurement?.measurement?.humidityAndTemperature as any;
        temp = humAndTemp["celciusTimes10"];
        hum = humAndTemp["relativeHumidityTimes100"];
      }
    }
    my.temperature = or(temp, -1270) / 10;
    my.humidity = or(hum, 20000) / 100;

    return my;
  }

  public static any(data: any): Ambient {
    let comp = pond.Component.fromObject(cloneDeep(data));
    let my = Ambient.createPond(comp);
    if (data && data.status && data.status.lastMeasurement) {
      my.status.lastMeasurement = data.status.lastMeasurement;
    }
    return my;
  }

  public update(other: Ambient) {
    this.settings = other.settings;
    this.status = other.status;
  }

  public static humidColour() {
    return describeMeasurement(
      quack.MeasurementType.MEASUREMENT_TYPE_PERCENT,
      quack.ComponentType.COMPONENT_TYPE_DHT
    ).colour();
  }

  public static tempColour() {
    return describeMeasurement(quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE).colour();
  }

  public name(): string {
    return this.settings.name !== "" ? this.settings.name : "Component " + this.key();
  }

  public key(): string {
    return this.settings.key;
  }

  public location(): quack.ComponentID {
    return quack.ComponentID.fromObject({
      type: this.settings.type,
      addressType: this.settings.addressType,
      address: this.settings.address
    });
  }

  public locationString(): string {
    return (
      or(this.settings.type, 0).toString() +
      "-" +
      or(this.settings.addressType, 0).toString() +
      "-" +
      or(this.settings.address, 0).toString()
    );
  }

  public type(): quack.ComponentType {
    return this.settings.type;
  }

  public subType(): number {
    return this.settings.subtype;
  }

  public getTempString(unit = pond.TemperatureUnit.TEMPERATURE_UNIT_CELSIUS): string {
    if (this.temperature < -126) return "--";
    if (unit === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT)
      return (this.temperature * (9 / 5) + 32).toFixed(2) + "°F";
    return this.temperature.toFixed(2) + "°C";
  }

  public getHumidityString(): string {
    if (this.humidity > 199) return "--";
    return this.humidity.toFixed(2) + "%";
  }

  public asComponent(): Component {
    let c = Component.create();
    c.settings = this.settings;
    c.status = this.status;
    return c;
  }
}
