import {
  DialogActions,
  DialogContent,
  DialogTitle,
  MenuItem,
  Select,
  TextField,
  Button,
  Grid2 as Grid,
  Box,
  InputAdornment,
  Stepper,
  Step,
  StepLabel,
  Tabs,
  Tab
} from "@mui/material";
import ResponsiveDialog from "common/ResponsiveDialog";
import { Terminal } from "models/Terminal";
import { Gate } from "models/Gate";
import { pond } from "protobuf-ts/pond";
import { useTerminalAPI, useGateAPI, useGlobalState } from "providers";
import React, { useEffect, useState } from "react";
import { useSnackbar } from "hooks";
//import { useHistory } from "react-router";
import { useNavigate } from "react-router-dom";

import DuctDescriber, { DuctOptions, FindDuctType } from "ducting/DuctDescriber";

interface DuctProps {
  diameter: number;
  length: number;
  thermalConductivity: number;
  thermalResistance: number;
  frictionFactor: number;
}

interface Props {
  open: boolean;
  close: (newGate?: Gate) => void;
  terminals?: Terminal[];
  gate?: Gate;
  long?: number;
  lat?: number;
}

const steps = ["Gate", "Duct"];

export default function GateSettings(props: Props) {
  const { open, close, terminals, gate, long, lat } = props;
  const [{as}] = useGlobalState();
  const [gateName, setGateName] = useState("");
  const [lowerFlowBound, setLowerFlowBound] = useState(0);
  const [upperFlowBound, setUpperFlowBound] = useState(0);
  const [terminalOptions, setTerminalOptions] = useState(terminals);
  const [terminalKey, setTerminalKey] = useState("");
  const gateAPI = useGateAPI();
  const terminalAPI = useTerminalAPI();
  const [loadingTerminals, setLoadingTerminals] = useState(false);
  const [removeDialog, setRemoveDialog] = useState(false);
  const { openSnack } = useSnackbar();
  //const history = useHistory();
  const navigate = useNavigate();
  const ductOptions = DuctOptions();
  const [ductType, setDuctType] = useState(0);
  const [ductName, setDuctName] = useState("");
  const [ductProps, setDuctProps] = useState<DuctProps>({
    diameter: 0,
    length: 0,
    frictionFactor: 0,
    thermalConductivity: 0,
    thermalResistance: 0
  });
  const [pcaUnit, setPcaUnit] = useState("");
  const [activeStep, setActiveStep] = useState(0);
  //user set identifier to be shown on the marker on the map
  const [terminalIdentifier, setTerminalIdentifier] = useState("");
  const [gateIdentifier, setGateIdentifier] = useState("");
  const [hourlyPCA, setHourlyPCA] = useState<number>(0);
  const [hourlyAPU, setHourlyAPU] = useState<number>(0);

  useEffect(() => {
    if (!terminals) {
      if (loadingTerminals) return;
      setLoadingTerminals(true);
      terminalAPI
        .listTerminals(500, 0, undefined, undefined, undefined, as)
        .then(resp => {
          setTerminalOptions(resp.data.terminals.map(a => Terminal.any(a)));
        })
        .catch(err => {})
        .finally(() => {
          setLoadingTerminals(false);
        });
    } else {
      setTerminalOptions(terminals);
    }
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [terminals, terminalAPI, as]);

  useEffect(() => {
    if (gate) {
      setGateName(gate.name);
      setTerminalKey(gate.terminal());
      setDuctProps({
        diameter: gate.settings.ductDiameter,
        length: gate.settings.ductLength,
        frictionFactor: gate.settings.frictionFactor,
        thermalConductivity: gate.settings.thermalConductivity,
        thermalResistance: gate.settings.thermalResistance
      });
      let currentType = FindDuctType(
        gate.settings.thermalResistance,
        gate.settings.thermalConductivity,
        gate.settings.frictionFactor
      );
      setDuctType(currentType);
      setLowerFlowBound(gate.lowerFlow());
      setUpperFlowBound(gate.upperFlow());
      setPcaUnit(gate.settings.pcaType);
      setDuctName(gate.settings.ductName);
      setTerminalIdentifier(gate.settings.letterIdentifier ?? "");
      setGateIdentifier(gate.settings.numberIdentifier ?? "");
      setHourlyAPU(gate.settings.hourlyApuCost ?? 0);
      setHourlyPCA(gate.settings.hourlyPcaCost ?? 0);
    } else {
      setGateName("");
      setTerminalKey("");
    }
  }, [gate]);

  const confirm = () => {
    if (gate) {
      let settings = gate.settings;
      settings.terminal = terminalKey;
      settings.ductDiameter = ductProps.diameter;
      settings.ductLength = ductProps.length;
      settings.frictionFactor = ductProps.frictionFactor;
      settings.thermalConductivity = ductProps.thermalConductivity;
      settings.thermalResistance = ductProps.thermalResistance;
      settings.lowerFlow = lowerFlowBound;
      settings.upperFlow = upperFlowBound;
      settings.ductName = ductName;
      settings.pcaType = pcaUnit;
      settings.letterIdentifier = terminalIdentifier;
      settings.numberIdentifier = gateIdentifier.toString();
      settings.hourlyApuCost = hourlyAPU;
      settings.hourlyPcaCost = hourlyPCA;
      gateAPI
        .updateGate(gate.key, gateName, settings, as)
        .then(resp => {
          openSnack("Gate update");
          close();
        })
        .catch(err => {
          openSnack("Failed to update gate");
        });
    } else {
      let settings: pond.GateSettings = pond.GateSettings.create({
        longitude: long,
        latitude: lat,
        terminal: terminalKey,
        ductDiameter: ductProps.diameter,
        ductLength: ductProps.length,
        frictionFactor: ductProps.frictionFactor,
        thermalConductivity: ductProps.thermalConductivity,
        thermalResistance: ductProps.thermalResistance,
        lowerFlow: lowerFlowBound,
        upperFlow: upperFlowBound,
        ductName: ductName,
        pcaType: pcaUnit,
        letterIdentifier: terminalIdentifier,
        numberIdentifier: gateIdentifier.toString(),
        hourlyApuCost: hourlyAPU,
        hourlyPcaCost: hourlyPCA
      });
      gateAPI
        .addGate(gateName, settings, as)
        .then(resp => {
          openSnack("New gate added");
          let newGate = Gate.create(
            pond.Gate.create({ key: resp.data.key, name: gateName, settings: settings })
          );
          close(newGate);
        })
        .catch(err => {
          openSnack("There was a problem adding your gate");
        });
    }
  };

  const remove = () => {
    if (gate) {
      gateAPI
        .removeGate(gate.key, as)
        .then(resp => {
          openSnack("Gate Deleted");
        })
        .catch(err => {
          openSnack("Failed to delete gate");
        })
        .finally(() => {
          navigate("/terminals");
        });
    }
  };

  const stepper = () => {
    if (gate === undefined) {
      return (
        <Stepper activeStep={activeStep}>
          {steps.map(label => {
            const stepProps: { completed?: boolean } = {};
            const labelProps: {
              optional?: React.ReactNode;
            } = {};
            return (
              <Step key={label} {...stepProps}>
                <StepLabel {...labelProps}>{label}</StepLabel>
              </Step>
            );
          })}
        </Stepper>
      );
    }

    return (
      <Box display="flex" justifyContent="center" width="100%">
        <Tabs
          value={activeStep}
          onChange={(_, value) => setActiveStep(value)}
          indicatorColor="primary"
          textColor="primary"
          variant="fullWidth"
          aria-label="bin tabs"
          //classes={{ root: classes.tabs }}
        >
          {steps.map((step, i) => (
            <Tab key={i} label={step} aria-label={step} />
          ))}
        </Tabs>
      </Box>
    );
  };

  const stepperContent = (step: number) => {
    switch (step) {
      case 1:
        return ductProperties();
      default:
        return gateProperties();
    }
  };

  const gateProperties = () => {
    //build list of letters for select box
    let tiOptions: JSX.Element[] = [];
    //adds the letters to the terminal id options
    for (let l = 65; l <= 90; l++) {
      tiOptions.push(
        <MenuItem key={String.fromCharCode(l)} value={String.fromCharCode(l)}>
          {String.fromCharCode(l)}
        </MenuItem>
      );
    }
    //add numbers 1-9 for terminal id options
    for (let n = 1; n <= 9; n++) {
      tiOptions.push(
        <MenuItem key={n} value={n}>
          {n}
        </MenuItem>
      );
    }
    let numberOptions: JSX.Element[] = [];
    for (let n = 0; n <= 99; n++) {
      numberOptions.push(
        <MenuItem key={n} value={n}>
          {n}
        </MenuItem>
      );
    }

    return (
      <React.Fragment>
        <TextField
          label="Gate Name"
          fullWidth
          value={gateName}
          onChange={e => setGateName(e.target.value)}
        />
        <Select
          id="terminal"
          label="Terminal"
          fullWidth
          displayEmpty
          value={terminalKey}
          onChange={e => {
            setTerminalKey(e.target.value as string);
          }}>
          <MenuItem key="new" value="">
            Select Terminal
          </MenuItem>
          {terminalOptions?.map(terminal => (
            <MenuItem key={terminal.key} value={terminal.key}>
              {terminal.name}
            </MenuItem>
          ))}
        </Select>
        <TextField
          label="Low Mass Air Flow"
          fullWidth
          type="number"
          value={lowerFlowBound}
          onChange={e => setLowerFlowBound(+e.target.value)}
        />
        <TextField
          label="High Mass Air Flow"
          fullWidth
          type="number"
          value={upperFlowBound}
          onChange={e => setUpperFlowBound(+e.target.value)}
        />
        <TextField
          label="PCA Unit"
          fullWidth
          value={pcaUnit}
          onChange={e => setPcaUnit(e.target.value)}
        />
        <TextField
          style={{ width: "45%" }}
          select
          label="Terminal Identifier"
          value={terminalIdentifier}
          onChange={e => {
            setTerminalIdentifier(e.target.value as string);
          }}>
          <MenuItem key="new" value="">
            Gate Letter
          </MenuItem>
          {tiOptions}
        </TextField>
        <TextField
          style={{ width: "45%", marginLeft: "10%" }}
          label="Gate Identifier"
          select
          value={gateIdentifier}
          onChange={e => setGateIdentifier(e.target.value)}>
          <MenuItem key="new" value="">
            Gate Number
          </MenuItem>
          {numberOptions}
        </TextField>
        <TextField
          label="Hourly PCA Cost"
          fullWidth
          type="number"
          value={hourlyPCA}
          InputProps={{
            endAdornment: <InputAdornment position="end">$/hr</InputAdornment>
          }}
          onChange={e => setHourlyPCA(+e.target.value)}
        />
        <TextField
          label="Hourly APU Cost"
          fullWidth
          type="number"
          value={hourlyAPU}
          InputProps={{
            endAdornment: <InputAdornment position="end">$/hr</InputAdornment>
          }}
          onChange={e => setHourlyAPU(+e.target.value)}
        />
      </React.Fragment>
    );
  };

  const ductProperties = () => {
    return (
      <React.Fragment>
        <TextField
          id="ductType"
          label="Duct Type"
          fullWidth
          value={ductType}
          select
          onChange={e => {
            let type = +e.target.value;
            setDuctType(type);
            setDuctName("custom");
            if (type > 1) {
              let describer = DuctDescriber(type);
              setDuctName(describer.name);
              setDuctProps({
                diameter: ductProps.diameter,
                frictionFactor: describer.frictionFactor,
                length: ductProps.length,
                thermalConductivity: describer.thermalConductivity,
                thermalResistance: describer.thermalResistance
              });
            }
          }}>
          <MenuItem key="new" value={pond.DuctType.DUCT_TYPE_INVALID}>
            Select Ducting Type
          </MenuItem>
          {ductOptions.map(duct => (
            <MenuItem key={duct.value} value={duct.value}>
              {duct.label}
            </MenuItem>
          ))}
          <MenuItem key="custom" value={pond.DuctType.DUCT_TYPE_NONE}>
            Custom
          </MenuItem>
        </TextField>
        <TextField
          margin="normal"
          id="ductDiameter"
          label="Duct Diameter(mm)"
          fullWidth
          type="text"
          value={isNaN(ductProps.diameter) ? "" : ductProps.diameter}
          error={isNaN(+ductProps.diameter)}
          InputProps={{
            endAdornment: <InputAdornment position="end">mm</InputAdornment>
          }}
          onChange={e => {
            setDuctProps({ ...ductProps, diameter: parseFloat(e.target.value) });
          }}
        />
        <TextField
          margin="normal"
          id="ductLength"
          label="Duct Length(m)"
          fullWidth
          type="text"
          value={isNaN(ductProps.length) ? "" : ductProps.length}
          error={isNaN(+ductProps.length)}
          InputProps={{
            endAdornment: <InputAdornment position="end">m</InputAdornment>
          }}
          onChange={e => {
            setDuctProps({ ...ductProps, length: parseFloat(e.target.value) });
          }}
        />
        <TextField
          margin="normal"
          id="thermalCond"
          label="Thermal Conductivity"
          fullWidth
          type="text"
          value={isNaN(ductProps.thermalConductivity) ? "" : ductProps.thermalConductivity}
          error={isNaN(+ductProps.thermalConductivity)}
          InputProps={{
            endAdornment: <InputAdornment position="end">W/mK</InputAdornment>
          }}
          onChange={e => {
            setDuctProps({ ...ductProps, thermalConductivity: parseFloat(e.target.value) });
            setDuctType(1);
            setDuctName("custom");
          }}
        />
        <TextField
          margin="normal"
          id="friction"
          label="Friction Factor"
          fullWidth
          type="text"
          value={isNaN(ductProps.frictionFactor) ? "" : ductProps.frictionFactor}
          error={isNaN(+ductProps.frictionFactor)}
          onChange={e => {
            setDuctProps({ ...ductProps, frictionFactor: parseFloat(e.target.value) });
            setDuctType(1);
            setDuctName("custom");
          }}
        />
        <TextField
          margin="normal"
          id="thermalRes"
          label="Thermal Resistance"
          fullWidth
          type="text"
          value={isNaN(ductProps.thermalResistance) ? "" : ductProps.thermalResistance}
          error={isNaN(+ductProps.thermalResistance)}
          InputProps={{
            endAdornment: <InputAdornment position="end">K/W</InputAdornment>
          }}
          onChange={e => {
            setDuctProps({ ...ductProps, thermalResistance: parseFloat(e.target.value) });
            setDuctType(1);
            setDuctName("custom");
          }}
        />
      </React.Fragment>
    );
  };

  const removeConfirmation = () => {
    return (
      <ResponsiveDialog open={removeDialog} onClose={() => setRemoveDialog(false)}>
        <DialogTitle>Delete Gate</DialogTitle>
        <DialogContent>Are you sure you wish to delete this gate?</DialogContent>
        <DialogActions>
          <Button
            onClick={() => {
              setRemoveDialog(false);
            }}>
            Cancel
          </Button>
          <Button onClick={remove}>Confirm</Button>
        </DialogActions>
      </ResponsiveDialog>
    );
  };

  return (
    <ResponsiveDialog open={open} onClose={() => close()}>
      {removeConfirmation()}
      <DialogTitle></DialogTitle>
      <DialogContent>
        {stepper()}
        {stepperContent(activeStep)}
      </DialogContent>
      <DialogActions>
        <Grid container direction="row">
          <Grid>
            {gate && (
              <Button
                variant="contained"
                style={{
                  backgroundColor: "red"
                }}
                onClick={() => {
                  setRemoveDialog(true);
                }}>
                Delete
              </Button>
            )}
          </Grid>
          <Grid>
            {(gate || activeStep === 0) && (
              <Button
                onClick={() => {
                  close();
                }}>
                Cancel
              </Button>
            )}
            {!gate && activeStep > 0 && (
              <Button
                onClick={() => {
                  setActiveStep(activeStep - 1);
                }}>
                Back
              </Button>
            )}
            {(gate || activeStep === 1) && (
              <Button variant="contained" color="primary" onClick={confirm}>
                Confirm
              </Button>
            )}
            {!gate && activeStep === 0 && (
              <Button
                variant="contained"
                color="primary"
                onClick={() => {
                  setActiveStep(activeStep + 1);
                }}>
                Next
              </Button>
            )}
          </Grid>
        </Grid>
      </DialogActions>
    </ResponsiveDialog>
  );
}
