import { LineData, Point } from "charts/measurementCharts/MultiLineGraph";
import { convertedUnitMeasurement } from "models/UnitMeasurement";
import moment, { Moment } from "moment";
import {
  ComponentMeasurement,
  ComponentTypeExtension,
  unitMeasurementSummaries,
  unitMeasurementSummary,
  Summary,
  GraphFilters,
  simpleAreaChartData,
  AreaChartData,
  simpleLineChartData,
  LineChartData
} from "pbHelpers/ComponentType";
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
import { pond } from "protobuf-ts/pond";
import { quack } from "protobuf-ts/quack";
import { avg } from "utils";

export function dragerGasDongle(subtype: number = 0): ComponentTypeExtension {
  let ppm = describeMeasurement(
    quack.MeasurementType.MEASUREMENT_TYPE_PPM,
    quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE,
    subtype
  );
  let voltage = describeMeasurement(
    quack.MeasurementType.MEASUREMENT_TYPE_VOLTAGE,
    quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE,
    subtype
  );

  let measurementTypes = [
    {
      measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PPM,
      label: ppm.label(),
      colour: ppm.colour(),
      graphType: ppm.graph()
    } as ComponentMeasurement,
    {
      measurementType: quack.MeasurementType.MEASUREMENT_TYPE_VOLTAGE,
      label: voltage.label(),
      colour: voltage.colour(),
      graphType: voltage.graph()
    } as ComponentMeasurement
  ];

  return {
    type: quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE,
    subtypes: [
      // {
      //   key: quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_NONE,
      //   value: "DRAGER_GAS_DONGLE_SUBTYPE_NONE",
      //   friendlyName: "Drager Gas Chain"
      // },
      // {
      //   key: quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_DEBUG_VOLTAGE,
      //   value: "DRAGER_GAS_DONGLE_SUBTYPE_ADVANCED",
      //   friendlyName: "Drager Gas Chain - Voltage Debug"
      // },
      // {
      //   key: quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_CO_CO2_NO2_O2,
      //   value: "DRAGER_GAS_DONGLE_SUBTYPE_ADVANCED",
      //   friendlyName: "Drager Gas Chain (CO CO2 NO2 O2)"
      // }
      {
        key: quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_CO,
        value: "DRAGER_GAS_DONGLE_SUBTYPE_CO",
        friendlyName: "Drager Gas CO"
      },
      {
        key: quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_CO2,
        value: "DRAGER_GAS_DONGLE_SUBTYPE_CO2",
        friendlyName: "Drager Gas CO2"
      },
      {
        key: quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_NO2,
        value: "DRAGER_GAS_DONGLE_SUBTYPE_NO2",
        friendlyName: "Drager Gas NO2"
      },
      {
        key: quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_O2,
        value: "DRAGER_GAS_DONGLE_SUBTYPE_O2",
        friendlyName: "Drager Gas O2"
      },
      {
        key: quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_H2S,
        value: "DRAGER_GAS_DONGLE_SUBTYPE_H2S",
        friendlyName: "Drager Gas H2S"
      },
      {
        key: quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_LEL,
        value: "DRAGER_GAS_DONGLE_SUBTYPE_LEL",
        friendlyName: "Drager Gas LEL"
      }
    ],
    friendlyName: "Drager Gas",
    description: "Drager Sensor that measures density of gases",
    isController: false,
    isSource: true,
    isArray: true,
    isCalibratable: false,
    addressTypes: [quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY, quack.AddressType.ADDRESS_TYPE_I2C],
    interactionResultTypes: [],
    states: [],
    //this is apparently used by the interactions to determine what the possible options for measurement type are
    measurements: measurementTypes,
    //believe this is only used with the old deprecated measurements system, unit measurements builds the summary in the UnitMeasurementSummary component
    measurementSummary: () => {},
    unitMeasurementSummary: (
      measurements: convertedUnitMeasurement
    ): Summary[] => {
      //if it is O2 display percentage rather than ppm
      if (subtype === quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_O2 || subtype === quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_LEL) {
        let summaries: Summary[] = [];
        measurements.measurementsFor.forEach(measurement => {
          let describer = describeMeasurement(
            measurement.type,
            quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE,
            subtype
          );
          //create the custom O2% summary
          if (measurement.type === quack.MeasurementType.MEASUREMENT_TYPE_PPM) {
            //convert vals to percent (should only be one value but because it is still an array)
            let vals: string[] = [];
            measurement.values.forEach(val => {
              //convert the value from ppm to percent
              vals.push(val / 10000 + "%");
            });
            summaries.push({
              colour: describer.colour(),
              label: describer.label(),
              type: measurement.type,
              value: vals,
              error: measurement.error
            });
          } else {
            //create the simple summary for the voltage
            summaries.push(unitMeasurementSummary(measurement, describer));
          }
        });

        return summaries;
      } else {
        return unitMeasurementSummaries(
          measurements,
          quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE,
          subtype
        );
      }
    },
    areaChartData: (
      measurement: pond.UnitMeasurementsForComponent,
      smoothingAverages?: number,
      filters?: GraphFilters
    ): AreaChartData => {
      return simpleAreaChartData(measurement, smoothingAverages, filters);
    },
    lineChartData: (
      measurement: pond.UnitMeasurementsForComponent,
      smoothingAverages?: number,
      filters?: GraphFilters
    ): LineChartData => {
      let chartData: LineChartData = {
        lines: [],
        average: []
      };
      //sets the value as a percent for the chart data
      if (subtype === quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_O2 || subtype === quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_LEL) {
        let firstTime: Moment | undefined;
        let lastTime: Moment | undefined;
        let valMap: Map<number, number[]> = new Map<number, number[]>();
        measurement.values.forEach((vals, i) => {
          let avgVals: Point[] = [];
          let newLineData: LineData = {
            timestamp: moment(measurement.timestamps[i]).valueOf(),
            points: vals.values.map((val, i) => ({ value: val / 10000, node: i }))
          };
          chartData.lines.push(newLineData);
          vals.values.forEach((val, k) => {
            let entry = valMap.get(k);
            if (entry) {
              entry.push(val);
              if (entry.length === smoothingAverages) {
                lastTime = moment(measurement.timestamps[i]);
                avgVals.push({
                  node: k,
                  value: avg(entry)
                });
              }
            } else {
              valMap.set(k, [val]);
              firstTime = moment(measurement.timestamps[i]);
            }
          });
          if (firstTime && lastTime) {
            chartData.average.push({
              points: avgVals,
              timestamp:
                Math.abs(firstTime.diff(lastTime)) / 2 +
                Math.min(firstTime.valueOf(), lastTime.valueOf())
            });
            firstTime = undefined;
            lastTime = undefined;
            valMap = new Map<number, number[]>();
          }
        });
      } else {
        chartData = simpleLineChartData(
          quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE,
          measurement,
          smoothingAverages,
          filters
        );
      }
      return chartData;
    },
    minMeasurementPeriodMs: 1000
  };
}
