import { pond } from "protobuf-ts/pond";
import { quack } from "protobuf-ts/pond";
import { or } from "utils/types";
import { cloneDeep } from "lodash";
import { getSubtypes } from "pbHelpers/ComponentType";
import { getFriendlyAddressTypeName, getHumanReadableAddress } from "pbHelpers/AddressType";
// import { getSubtypes } from "pbHelpers/ComponentType";

export class Component {
  public settings: pond.ComponentSettings = pond.ComponentSettings.create();
  public status: pond.ComponentStatus = pond.ComponentStatus.create();
  public lastMeasurement: pond.UnitMeasurementsForComponent[] = [];
  public lastGoodMeasurement: pond.UnitMeasurementsForComponent[] = [];
  public permissions: pond.Permission[] = [];

  public static create(pb?: pond.Component): Component {
    let my = new Component();
    if (pb) {
      my.settings = pond.ComponentSettings.fromObject(
        or(pb.settings, pond.ComponentSettings.create())
      );
      my.status = pond.ComponentStatus.fromObject(or(pb.status, pond.ComponentStatus.create()));
      my.lastMeasurement = pb.lastMeasurement ?? pond.UnitMeasurementsForComponent.create();
      //my.lastGoodMeasurement = pb.status?.lastGoodMeasurement ?? pond.UnitMeasurementsForComponent.create();
      my.permissions = pb.permissions ?? [];
    }
    return my;
  }

  public static clone(other?: Component): Component {
    if (other) {
      return Component.create(
        pond.Component.fromObject(cloneDeep({ settings: other.settings, status: other.status }))
      );
    }
    return Component.create();
  }

  public static any(data: any): Component {
    let my = Component.create(pond.Component.fromObject(cloneDeep(data)));
    if (data && data.status && data.status.lastMeasurement) {
      my.status.lastMeasurement = data.status.lastMeasurement;
    }
    if (data && data.status && data.status.lastGoodMeasurement) {
      my.status.lastGoodMeasurement = [];
      data.status.lastGoodMeasurement.forEach((m: any) => {
        my.status.lastGoodMeasurement.push(m);
      });
    }
    return my;
  }

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

  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,
      expansionLine: this.settings.expansionLine,
      muxLine: this.settings.muxLine
    });
  }

  public locationString(): string {
    let compositeLocation = or(this.settings.type, 0).toString() +
      "-" +
      or(this.settings.addressType, 0).toString() +
      "-" +
      or(this.settings.address, 0).toString()
    if(this.settings.expansionLine){
      compositeLocation = compositeLocation + "-" + this.settings.expansionLine
    }
      if(this.settings.muxLine){
      compositeLocation = compositeLocation + ":" + this.settings.muxLine
    }
    return compositeLocation;
  }

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

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

  public subTypeName(): string {
    let subtypes = getSubtypes(this.settings.type);
    let subName = "Default";
    subtypes.forEach(sub => {
      if (this.settings.subtype === sub.key) {
        subName = sub.friendlyName;
      }
    });
    return subName;
  }

  public numNodes(): number {
    if (this.lastMeasurement[0] && this.lastMeasurement[0].values[0]) {
      return this.lastMeasurement[0].values[0].values.length;
    }
    return 0;
  }

  public addressDescription(deviceProduct?: pond.DeviceProduct): string {
      if (
        this.settings.addressType === quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY ||
        (this.settings.addressType >= quack.AddressType.ADDRESS_TYPE_PIN_OFFSET1 &&
          this.settings.addressType <= quack.AddressType.ADDRESS_TYPE_PIN_OFFSET100)
      ) {
        let addressDescription = getHumanReadableAddress(
          this.settings.addressType,
          this.settings.type,
          this.settings.address,
          deviceProduct
        );
        if (addressDescription === "") {
          addressDescription = "Internal";
        }
        let port = "Port: " + addressDescription;
        let cableID = "";
        if (
          this.settings.addressType >= quack.AddressType.ADDRESS_TYPE_PIN_OFFSET1 &&
          this.settings.addressType <= quack.AddressType.ADDRESS_TYPE_PIN_OFFSET100
        ) {
          cableID = "Cable: " + (this.settings.addressType - 8);
        }
        return port + " " + cableID;
      } else {
        return getFriendlyAddressTypeName(this.settings.addressType);
      }
    };
}
