import { Button, DialogActions, DialogContent, DialogTitle, Typography } from "@mui/material";
import ResponsiveDialog from "common/ResponsiveDialog";
import { Component, Device } from "models";
import { Gate } from "models/Gate";
import moment from "moment";
import { pond, quack } from "protobuf-ts/pond";
import { useGlobalState, useInteractionsAPI, useSnackbar } from "providers";
import React, { useEffect, useState } from "react";

interface Props {
  open: boolean;
  close: (canceled: boolean) => void;
  gate: Gate;
  compDevice: pond.ComprehensiveDevice;
  densityTemp: number;
}

//map that the temp is the key and the air density is the value
const densityMap = new Map<number, number>([
  [35, 1.15],
  [30, 1.16],
  [25, 1.18],
  [20, 1.2],
  [15, 1.23],
  [10, 1.25],
  [5, 1.27],
  [0, 1.29],
  [-5, 1.32],
  [-10, 1.34],
  [-15, 1.37],
  [-20, 1.39],
  [-25, 1.42]
]);

//this entire component will only be used for manual setting of each device on the gate
//once we have numbers for presets it may never be used again
export default function GateDeviceInteraction(props: Props) {
  const { open, close, gate, compDevice, densityTemp } = props;
  const [{ user, as }] = useGlobalState();
  const [lowDelta, setLowDelta] = useState(0);
  const [highDelta, setHighDelta] = useState(0);
  const [greenComponent, setGreenComponent] = useState<Component>();
  const [redComponent, setRedComponent] = useState<Component>();
  const [pressureComponent, setPressureComponent] = useState<Component>();
  const interactionsAPI = useInteractionsAPI();
  const [adding, setAdding] = useState(false);
  const { openSnack } = useSnackbar();

  useEffect(() => {
    //math to determine what the delta pressures to set will be
    let celciusTemp = densityTemp;
    if (user.settings.temperatureUnit === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
      celciusTemp = densityTemp * 1.8 + 32;
    }
    let roundedTemp = Math.round(celciusTemp / 5) * 5;
    let airDensity = densityMap.get(roundedTemp);
    //have default values if the temp is outside the map
    if (roundedTemp > 35 && airDensity === undefined) airDensity = 1.1;
    if (roundedTemp < -25 && airDensity === undefined) airDensity = 1.5;

    //calculate the c value for the equation
    if (airDensity !== undefined) {
      let diameterM = gate.ductDiameter() / 1000;
      let pieRadSquare = 3.14 * Math.pow(diameterM / 2, 2);
      let c = 0.98 * pieRadSquare * Math.sqrt(2 * airDensity);
      let qmHigh = gate.upperFlow();
      let qmLow = gate.lowerFlow();

      setLowDelta(Math.round(Math.pow(qmLow / c, 2)));
      setHighDelta(Math.round(Math.pow(qmHigh / c, 2)));
    }

    //addresses of controller LEDs on a V1 device
    let redAddr = "3-1-512";
    let greenAddr = "3-1-1024";
    if (compDevice.device) {
      let dev = Device.create(compDevice.device);
      if (dev.settings.product === pond.DeviceProduct.DEVICE_PRODUCT_MIPCA_V2) {
        redAddr = "3-1-256";
        greenAddr = "3-1-512";
      }
    }

    //need to find if they have LED's in both of the controller positions
    compDevice.components.forEach(comp => {
      let component = Component.any(comp);
      //checks the address for the LED components to get the red and green LED's

      if (component.locationString() === redAddr && component.subType() === 1) {
        setRedComponent(component);
      } else if (component.locationString() === greenAddr && component.subType() === 1) {
        setGreenComponent(component);
      } else if (component.type() === quack.ComponentType.COMPONENT_TYPE_PRESSURE_CABLE) {
        if (
          gate.preferences[component.key()] === pond.GateComponentType.GATE_COMPONENT_TYPE_PRESSURE
        ) {
          setPressureComponent(component);
        }
      }
    });
  }, [gate, densityTemp, user, compDevice]);

  // useEffect(() => {
  //   //load current interactions for the device
  //   let deviceID = Device.any(compDevice.device).id();
  //   interactionsAPI.listInteractionsByDevice(deviceID).then(resp => {
  //     setCurrentInteractions(resp);
  //   });
  // }, [compDevice.device, interactionsAPI]);

  // const removeCurrentInteractions = () => {
  //   let deviceID = Device.any(compDevice.device).id();
  //   currentInteractions.forEach(interaction => {
  //     interactionsAPI.removeInteraction(deviceID, interaction.key());
  //   });
  // };

  const createInteractions = async () => {
    //the interactions to be made

    //TOGGLE green ON when pressure within range of upper and lower
    if (
      greenComponent !== undefined &&
      redComponent !== undefined &&
      pressureComponent !== undefined
    ) {
      let greenToggle: pond.InteractionSettings = pond.InteractionSettings.create({
        sink: quack.ComponentID.create({
          type: greenComponent.type(),
          address: greenComponent.settings.address,
          addressType: greenComponent.settings.addressType
        }),
        source: quack.ComponentID.create({
          type: pressureComponent.type(),
          address: pressureComponent.settings.address,
          addressType: pressureComponent.settings.addressType
        }),
        conditions: [
          pond.InteractionCondition.create({
            comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
            value: -highDelta,
            measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
          }),
          pond.InteractionCondition.create({
            comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
            value: -lowDelta,
            measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
          })
        ],
        nodeOne: 2,
        nodeTwo: 1,
        subtype: 18,
        schedule: pond.InteractionSchedule.create({
          timezone: moment.tz.guess(),
          weekdays: ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"],
          timeOfDayStart: "00:00",
          timeOfDayEnd: "24:00"
        }),
        result: pond.InteractionResult.create({
          type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_TOGGLE,
          value: 1
        })
      });

      //TOGGLE red OFF when pressure within range of upper and lower
      let redToggle: pond.InteractionSettings = pond.InteractionSettings.create({
        sink: quack.ComponentID.create({
          type: redComponent.type(),
          address: redComponent.settings.address,
          addressType: redComponent.settings.addressType
        }),
        source: quack.ComponentID.create({
          type: pressureComponent.type(),
          address: pressureComponent.settings.address,
          addressType: pressureComponent.settings.addressType
        }),
        conditions: [
          pond.InteractionCondition.create({
            comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
            value: -highDelta,
            measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
          }),
          pond.InteractionCondition.create({
            comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
            value: -lowDelta,
            measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
          })
        ],
        nodeOne: 2,
        nodeTwo: 1,
        subtype: 18,
        schedule: pond.InteractionSchedule.create({
          timezone: moment.tz.guess(),
          weekdays: ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"],
          timeOfDayStart: "00:00",
          timeOfDayEnd: "24:00"
        }),
        result: pond.InteractionResult.create({
          type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_TOGGLE,
          value: 0
        })
      });

      let deviceID = Device.any(compDevice.device).id();
      if (deviceID !== undefined) {
        let multi = pond.MultiInteractionSettings.create({
          interactions: [greenToggle, redToggle]
        });
        interactionsAPI
          .addMultiInteractions(deviceID, multi, as)
          .then(resp => {
            openSnack("Interactions added");
          })
          .catch(err => {
            openSnack("There was a problem adding interactions to the device");
          })
          .finally(() => {
            setAdding(false);
          });
      }
    }
    close(false);
  };

  return (
    <ResponsiveDialog
      open={open}
      onClose={() => {
        close(true);
      }}>
      <DialogTitle>Set Interaction For Light Toggle</DialogTitle>
      <DialogContent>
        Your Delta Pressures, in pascals, will be:
        <Typography>low = {lowDelta}</Typography>
        <Typography>high = {highDelta}</Typography>
        <Typography>{greenComponent ? "" : "Green LED Component not found"}</Typography>
        <Typography>{redComponent ? "" : "Red LED Component not found"}</Typography>
      </DialogContent>
      <DialogActions>
        <Button
          variant="contained"
          color="primary"
          onClick={() => {
            //TODO: Once we figure out how to fix the backend to handle rapid addition/removal of interactions
            //removeCurrentInteractions();
            setAdding(true);
            createInteractions();
          }}
          disabled={greenComponent === undefined || redComponent === undefined || adding}>
          {adding ? "Adding Interaction" : "Create Interaction"}
        </Button>
      </DialogActions>
    </ResponsiveDialog>
  );
}
