import { GraphType } from "common/Graph";
import { convertedUnitMeasurement } from "models/UnitMeasurement";
import {
  AreaChartData,
  ComponentMeasurement,
  ComponentTypeExtension,
  GraphFilters,
  LineChartData,
  simpleAreaChartData,
  simpleLineChartData,
  simpleMeasurement,
  Summary,
  unitMeasurementSummaries
} from "pbHelpers/ComponentType";
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
import { pond } from "protobuf-ts/pond";
import { quack } from "protobuf-ts/quack";

interface Node {
  frequency: number;
  singleAcceleration: number;
}

function extractNodes(measurement: quack.IMeasurement | null | undefined): Node[] {
  let measurements: Node[] = [];
  if (measurement && measurement.vibrationCable) {
    for (let i = 0; i < measurement.vibrationCable.frequency.length; i++) {
      measurements.push({
        frequency: measurement.vibrationCable.frequency[i],
        singleAcceleration: measurement.vibrationCable.singleAccelerationRms[i]
      });
    }
  }

  return measurements;
}

export function VibrationCable(subtype: number = 0): ComponentTypeExtension {
  let frequency = describeMeasurement(
    quack.MeasurementType.MEASUREMENT_TYPE_FREQUENCY,
    quack.ComponentType.COMPONENT_TYPE_VIBRATION_CHAIN,
    subtype
  );
  let singleAccelerationRMS = describeMeasurement(
    quack.MeasurementType.MEASUREMENT_TYPE_SINGLE_ACCELERATION_RMS,
    quack.ComponentType.COMPONENT_TYPE_VIBRATION_CHAIN,
    subtype
  );
  let totalAccelerationRMS = describeMeasurement(
    quack.MeasurementType.MEASUREMENT_TYPE_TOTAL_ACCELERATION_RMS,
    quack.ComponentType.COMPONENT_TYPE_VIBRATION_CHAIN,
    subtype
  );
  return {
    type: quack.ComponentType.COMPONENT_TYPE_VIBRATION_CHAIN,
    subtypes: [],
    friendlyName: "Vibration Cable",
    description: "Measures frequency and peaks of vibration",
    isController: false,
    isSource: true,
    isArray: true,
    isCalibratable: false,
    addressTypes: [quack.AddressType.ADDRESS_TYPE_SPI],
    interactionResultTypes: [],
    states: [],
    measurements: [
      //frequency measurements
      {
        measurementType: quack.MeasurementType.MEASUREMENT_TYPE_FREQUENCY,
        label: frequency.label(),
        graphType: GraphType.AREA,
        colour: frequency.colour(),
        extract: function(measurement: quack.Measurement, filters?: GraphFilters): any {
          let frequency = extractNodes(measurement).map(n => n.frequency);

          let frequencyMeasurements: any = {
            low: Math.min(...frequency),
            high: Math.max(...frequency)
          };

          frequency.forEach((measurement, i) => {
            frequencyMeasurements["node" + i] = measurement;
          });

          return frequencyMeasurements;
        },
        isErrorMeasurement: (measurement: quack.Measurement): boolean => {
          //TODO determine what the error value would be
          return false;
        }
      } as ComponentMeasurement,
      //single accelration
      {
        measurementType: quack.MeasurementType.MEASUREMENT_TYPE_SINGLE_ACCELERATION_RMS,
        label: singleAccelerationRMS.label(),
        graphType: GraphType.AREA,
        colour: singleAccelerationRMS.colour(),
        extract: function(measurement: quack.Measurement, filters?: GraphFilters): any {
          let frequency = extractNodes(measurement).map(n => n.singleAcceleration);

          let frequencyMeasurements: any = {
            low: Math.min(...frequency),
            high: Math.max(...frequency)
          };

          frequency.forEach((measurement, i) => {
            frequencyMeasurements["node" + i] = measurement;
          });

          return frequencyMeasurements;
        },
        isErrorMeasurement: (measurement: quack.Measurement): boolean => {
          //TODO determine what the error value would be
          return false;
        }
      } as ComponentMeasurement,
      //total acceleration
      simpleMeasurement(totalAccelerationRMS)
    ],
    //believe this is only used with the old deprecated measurements system, unit measurements builds the summary in the UnitMeasurementSummary component
    measurementSummary: async function() {},
    unitMeasurementSummary: (
      measurements: convertedUnitMeasurement,
    ): Summary[] => {
      return unitMeasurementSummaries(
        measurements,
        quack.ComponentType.COMPONENT_TYPE_VIBRATION_CHAIN,
        subtype,
      );
    },
    areaChartData: (
      measurement: pond.UnitMeasurementsForComponent,
      smoothingAverages?: number,
      filters?: GraphFilters
    ): AreaChartData => {
      return simpleAreaChartData(measurement, smoothingAverages, filters);
    },
    lineChartData: (
      measurement: pond.UnitMeasurementsForComponent,
      smoothingAverages?: number,
      filters?: GraphFilters
    ): LineChartData => {
      return simpleLineChartData(
        quack.ComponentType.COMPONENT_TYPE_VIBRATION_CHAIN,
        measurement,
        smoothingAverages,
        filters
      );
    },
    minMeasurementPeriodMs: 1000
  };
}
