import { pond, quack } from "protobuf-ts/pond";
import { stringToComponentId } from "./Component";
import { capitalize } from "utils/strings";
import { or } from "utils";

interface BinShapeDescriber {
  key: pond.BinShape;
  label: string;
}

export const GetBinShapeDescribers = (): BinShapeDescriber[] => {
  return [
    { key: pond.BinShape.BIN_SHAPE_UNKNOWN, label: "Unknown" },
    { key: pond.BinShape.BIN_SHAPE_FLAT_BOTTOM, label: "Flat Bottom" },
    { key: pond.BinShape.BIN_SHAPE_HOPPER_BOTTOM, label: "Hopper" }
  ];
};

// DEPRECATED -- the bon now knows its components from the relative object table
export const HasGrainCable = (bin?: pond.BinSettings): boolean => {
  if (bin && bin.deviceComponents) {
    bin.deviceComponents.forEach(dc => {
      dc.components.forEach(c => {
        if (stringToComponentId(c).type === quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE)
          return true;
      });
    });
  }

  return false;
};

export const HasPlenumSensor = (bin?: pond.BinSettings): boolean => {
  if (bin && bin.deviceComponents) {
    bin.deviceComponents.forEach(dc => {
      dc.components.forEach(c => {
        let component = stringToComponentId(c);
        if (component.type === quack.ComponentType.COMPONENT_TYPE_DHT) return true;
      });
    });
  }

  return false;
};

const keyTranslator = new Map<keyof pond.BinSettings, string>([
  ["name", "Name"],
  ["specs", "Specifications"],
  ["mode", "Mode of Operation"],
  ["fan", "Fan Type"],
  ["location", "Location"],
  ["inventory", "Inventory"],
  ["deviceComponents", "Device Components"]
]);

// Keys will be stringified by default if not found in the keyTranslator
export function TranslateKey(key: keyof pond.BinSettings): string {
  let translatedKey = keyTranslator.get(key);
  return translatedKey ? translatedKey : capitalize(key.toString());
}

const valueTranslator = new Map<keyof pond.BinSettings, (device: pond.BinSettings) => string>([
  ["name", device => device.name],
  [
    "specs",
    device => {
      let s: string = "";
      if (device.specs) {
        s = s + "Capacity:  " + device.specs.bushelCapacity + " (bu)";
        switch (device.specs.shape) {
          case pond.BinShape.BIN_SHAPE_FLAT_BOTTOM:
            s = s + "\nShape:  Flat Bottom";
            break;
          case pond.BinShape.BIN_SHAPE_HOPPER_BOTTOM:
            s = s + "\nShape:  Hopper Bottom";
            break;
          default:
            s = s + "Unknown";
        }
        s = s + "\nHeight:  " + device.specs.heightCm + " (cm)";
        s = s + "\nDiameter:  " + device.specs.diameterCm + " (cm)";
      }
      return s;
    }
  ],
  [
    "mode",
    device => {
      if (device.mode === undefined) {
        return "None";
      }
      if (device.mode === null) {
        return "None";
      }
      switch (device.mode) {
        case pond.BinMode.BIN_MODE_COOLDOWN:
          return "Cool Down";
        case pond.BinMode.BIN_MODE_DRYING:
          return "Drying";
        case pond.BinMode.BIN_MODE_NONE:
          return "None";
        case pond.BinMode.BIN_MODE_STORAGE:
          return "Storage";
        case pond.BinMode.BIN_MODE_HYDRATING:
          return "Hydrating";
        default:
          return "None";
      }
    }
  ],
  [
    "fan",
    device => {
      switch (device.fan?.type) {
        case pond.FanType.FAN_TYPE_CENTRIFUGAL_HIGH_SPEED:
          return "Centrifugal High Speed";
        case pond.FanType.FAN_TYPE_CENTRIFUGAL_INLINE:
          return "Centrifugal Inline";
        case pond.FanType.FAN_TYPE_CENTRIFUGAL_LOW_SPEED:
          return "Centrifugal Low Speed";
        case pond.FanType.FAN_TYPE_UNKNOWN:
          return "Unknown";
        default:
          return "None";
      }
    }
  ],
  [
    "location",
    device => {
      let long = device.location?.longitude;
      let lat = device.location?.latitude;
      if (long && lat) {
        return "Long: " + Math.round(long * 100) / 100 + ", Lat: " + Math.round(lat * 100) / 100;
      }
      return "No coords to compare";
    }
  ],
  [
    "inventory",
    device => {
      let s: string = "";
      if (device.inventory) {
        s = s + "Grain Type:  ";
        switch (device.inventory.grainType) {
          case pond.Grain.GRAIN_BARLEY:
            s = s + "Barley,\n";
            break;
          case pond.Grain.GRAIN_BUCKWHEAT:
            s = s + "Buckwheat,\n";
            break;
          case pond.Grain.GRAIN_CANOLA:
            s = s + "Canola,\n";
            break;
          default:
            s = s + "Grain,\n";
        }
        s = s + "Use:  ";
        switch (device.inventory.grainUse) {
          case pond.GrainUse.GRAIN_USE_COMMERCIAL:
            s = s + "Commercial,\n";
            break;
          case pond.GrainUse.GRAIN_USE_FEED:
            s = s + "Feed,\n";
            break;
          case pond.GrainUse.GRAIN_USE_SEED:
            s = s + "Seed,\n";
            break;
          default:
            s = s + "Unknown,\n";
        }
        s = s + "Amount:  " + device.inventory.grainBushels + " (bu)";
      }
      return s;
    }
  ],
  [
    "deviceComponents",
    device => {
      let s: string = "";
      device.deviceComponents.forEach(dev => {
        dev.components.forEach(comp => {
          s = s + comp + "\n";
        });
      });
      return s;
    }
  ],
  [
    "theme",
    device => {
      return "Bin Theme";
    }
  ]
]);

// Values will be stringified by default if its key is not found in the valueTranslator
export function TranslateValue(key: keyof pond.BinSettings, device: pond.BinSettings) {
  let translatorFunc = valueTranslator.get(key);
  let value: any = or(device[key], "");
  let d: string;
  d = or(value.toString(), "");
  return translatorFunc ? translatorFunc(device) : device[key] ? capitalize(d) : "";
}
