import { amber } from "@mui/material/colors";
import { GraphType } from "common/Graph";
import {
  ComponentMeasurement,
  ComponentTypeExtension,
  Subtype,
  Summary,
  simpleSummaries,
  unitMeasurementSummaries,
  AreaChartData,
  GraphFilters,
  simpleAreaChartData,
  LineChartData,
  simpleLineChartData
} from "pbHelpers/ComponentType";
import { quack } from "protobuf-ts/quack";
import { or } from "utils/types";
import { describeMeasurement, MeasurementDescriber } from "pbHelpers/MeasurementDescriber";
import WindSpeedDark from "assets/components/windSpeedDark.png";
import WindSpeedLight from "assets/components/windSpeedLight.png";
import RainFallDark from "assets/components/rainFallDark.png";
import RainFallLight from "assets/components/rainFallLight.png";
import { convertedUnitMeasurement } from "models/UnitMeasurement";
import { pond } from "protobuf-ts/pond";

export function Trigger(subtype: number = 0): ComponentTypeExtension {
  let trigger = describeMeasurement(
    quack.MeasurementType.MEASUREMENT_TYPE_BOOLEAN,
    quack.ComponentType.COMPONENT_TYPE_EDGE_TRIGGERED,
    subtype
  );
  let windTrigger = describeMeasurement(
    quack.MeasurementType.MEASUREMENT_TYPE_SPEED,
    quack.ComponentType.COMPONENT_TYPE_EDGE_TRIGGERED,
    subtype
  );
  let rainTrigger = describeMeasurement(
    quack.MeasurementType.MEASUREMENT_TYPE_RAIN,
    quack.ComponentType.COMPONENT_TYPE_EDGE_TRIGGERED,
    subtype
  );

  let currentTrigger: MeasurementDescriber;
  let states: string[];
  let stateLabel: string;
  let gType;
  let mType;
  let myIcon;
  switch (subtype) {
    case quack.EdgeTriggeredSubtype.EDGE_TRIGGERED_SUBTYPE_WIND_SPEED:
      currentTrigger = windTrigger;
      states = [];
      stateLabel = "Wind Speed";
      gType = GraphType.LINEAR;
      mType = quack.MeasurementType.MEASUREMENT_TYPE_SPEED;
      myIcon = (theme?: "light" | "dark") => {
        return theme === "light" ? WindSpeedDark : WindSpeedLight;
      };
      break;
    case quack.EdgeTriggeredSubtype.EDGE_TRIGGERED_SUBTYPE_RAIN:
      currentTrigger = rainTrigger;
      states = [];
      stateLabel = "Rain";
      gType = GraphType.BAR;
      mType = quack.MeasurementType.MEASUREMENT_TYPE_RAIN;
      myIcon = (theme?: "light" | "dark") => {
        return theme === "light" ? RainFallDark : RainFallLight;
      };
      break;
    default:
      currentTrigger = trigger;
      states = trigger.enumerations();
      stateLabel = "State Transitions";
      gType = GraphType.SCATTER;
      mType = quack.MeasurementType.MEASUREMENT_TYPE_BOOLEAN;
  }

  return {
    type: quack.ComponentType.COMPONENT_TYPE_EDGE_TRIGGERED,
    subtypes: [
      {
        key: quack.EdgeTriggeredSubtype.EDGE_TRIGGERED_SUBTYPE_NONE,
        value: "EDGE_TRIGGERED_SUBTYPE_NONE",
        friendlyName: "Generic Trigger"
      } as Subtype,
      {
        key: quack.EdgeTriggeredSubtype.EDGE_TRIGGERED_SUBTYPE_DOOR,
        value: "EDGE_TRIGGERED_SUBTYPE_DOOR",
        friendlyName: "Door"
      } as Subtype,
      {
        key: quack.EdgeTriggeredSubtype.EDGE_TRIGGERED_SUBTYPE_WATER,
        value: "EDGE_TRIGGERED_SUBTYPE_WATER",
        friendlyName: "Flow"
      } as Subtype,
      {
        key: quack.EdgeTriggeredSubtype.EDGE_TRIGGERED_SUBTYPE_RAIN,
        value: "EDGE_TRIGGERED_SUBTYPE_RAIN",
        friendlyName: "Rain"
      } as Subtype,
      {
        key: quack.EdgeTriggeredSubtype.EDGE_TRIGGERED_SUBTYPE_WIND_SPEED,
        value: "EDGE_TRIGGERED_SUBTYPE_WINDSPEED",
        friendlyName: "Wind Speed"
      } as Subtype
    ],
    friendlyName: "Trigger",
    description: "Measures state transitions",
    isController: false,
    isSource: true,
    isCalibratable: false,
    addressTypes: [quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY],
    interactionResultTypes: [],
    states: states,
    measurements: [
      {
        extract: function(measurement: quack.Measurement): any {
          if (!measurement || !measurement.edgeTriggered) {
            return null;
          }
          if (
            measurement.subtype === quack.EdgeTriggeredSubtype.EDGE_TRIGGERED_SUBTYPE_WIND_SPEED
          ) {
            let edge = measurement.edgeTriggered;
            let windSpeed = edge.rises ?? 0;
            return windSpeed;
          } else if (
            measurement.subtype === quack.EdgeTriggeredSubtype.EDGE_TRIGGERED_SUBTYPE_RAIN
          ) {
            return measurement.edgeTriggered.rises;
          } else {
            let edge = measurement.edgeTriggered;
            let value = edge.state ? 1 : 0;
            let bubble = edge.state ? or(edge.falls, 0) : or(edge.rises, 0);
            return { value, bubble };
          }
        },
        measurementType: mType,
        label: stateLabel,
        colour: amber["700"],
        graphType: gType,
        isErrorMeasurement: (measurement?: quack.Measurement | null) => {
          return currentTrigger.isErrorMeasurement(measurement);
        }
      } as ComponentMeasurement
    ],
    measurementSummary: async function(measurement: quack.Measurement): Promise<Array<Summary>> {
      return simpleSummaries(measurement, currentTrigger);
    },
    unitMeasurementSummary: (
      measurements: convertedUnitMeasurement,
    ): Summary[] => {
      return unitMeasurementSummaries(
        measurements,
        quack.ComponentType.COMPONENT_TYPE_EDGE_TRIGGERED,
        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_EDGE_TRIGGERED,
        measurement,
        smoothingAverages,
        filters
      );
    },
    minMeasurementPeriodMs: 1000,
    icon: myIcon
  };
}
