import {
  Button,
  DialogActions,
  DialogContent,
  DialogTitle,
  Grid2 as Grid,
  InputAdornment,
  Switch,
  TextField,
  Theme,
  useTheme
} from "@mui/material";
import { makeStyles } from "@mui/styles";
import ResponsiveDialog from "common/ResponsiveDialog";
import SearchSelect, { Option } from "common/SearchSelect";
import GrainDescriber, { GrainOptions, ToGrainOption } from "grain/GrainDescriber";
import GrainTransaction from "grain/GrainTransaction";
import { clone } from "lodash";
import { GrainBag } from "models/GrainBag";
import moment from "moment";
import { pond } from "protobuf-ts/pond";
import { useGlobalState, useGrainBagAPI, useSnackbar } from "providers";
import React, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { getGrainUnit } from "utils";

const useStyles = makeStyles((theme: Theme) => {
  return ({
    bottomSpacing: {
      marginBottom: theme.spacing(1)
    }
  })
});

interface Props {
  open: boolean;
  close: (updatedBag?: GrainBag) => void;
  coordinates?: { start: pond.Coordinates; end: pond.Coordinates };
  grainBag?: GrainBag;
}

export default function GrainBagSettings(props: Props) {
  const { open, close, grainBag, coordinates } = props;
  const classes = useStyles();
  const grainBagAPI = useGrainBagAPI();
  const [bagName, setBagName] = useState("");
  const [bagDiameterM, setBagDiameterM] = useState(0);
  const [bagLengthM, setBagLengthM] = useState(0);
  const [bagDiameterDisplay, setBagDiameterDisplay] = useState(0);
  const [bagLengthDispla, setBagLengthDisplay] = useState(0);
  const [{ user, as }] = useGlobalState();
  const [isCustom, setIsCustom] = useState<boolean>(false);
  const [customType, setCustomType] = useState("");
  const [supportedGrainType, setSupportedGrainType] = useState(pond.Grain.GRAIN_INVALID);
  const [selectedGrainOp, setSelectedGrainOp] = useState<Option | null>(null);
  const grainOptions = GrainOptions();
  const [grainSubtype, setGrainSubtype] = useState("");
  const [grainCapacity, setGrainCapacity] = useState(0);
  const [grainFill, setGrainFill] = useState("");
  const [grainBushels, setGrainBushels] = useState(0);
  const [fillDate, setFillDate] = useState(moment().format("YYYY-MM-DD"));
  const [initialMoisture, setInitialMoisture] = useState(0);
  // const history = useHistory();
  const navigate = useNavigate()
  const { openSnack } = useSnackbar();
  const theme = useTheme();
  const [grainUpdate, setGrainUpdate] = useState(false);
  const [grainDiff, setGrainDiff] = useState(0);
  const [bushelsPerTonne, setBushelsPerTonne] = useState(0);

  useEffect(() => {
    if (grainBag) {
      //if a grainbag is passed in set all the state values
      setBagDiameterM(grainBag.settings.diameter);
      setBagDiameterDisplay(
        user.settings.distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_FEET
          ? grainBag.settings.diameter * 3.281
          : grainBag.settings.diameter
      );
      setBagLengthM(grainBag.settings.length);
      setBagLengthDisplay(
        user.settings.distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_FEET
          ? grainBag.settings.length * 3.281
          : grainBag.settings.length
      );
      let grainVal = grainBag.bushels();
      if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT) {
        grainVal = grainBag.bushels() / grainBag.bushelsPerTonne();
      }
      setGrainFill(grainVal.toFixed(2));
      setBagName(grainBag.name());
      setIsCustom(grainBag.isCustom());
      setSupportedGrainType(grainBag.settings.supportedGrain);
      setSelectedGrainOp(ToGrainOption(grainBag.settings.supportedGrain));
      setCustomType(grainBag.settings.customGrain);
      setGrainSubtype(grainBag.settings.grainSubtype);
      setGrainCapacity(grainBag.capacity());
      setGrainBushels(grainBag.bushels());
      setFillDate(grainBag.settings.fillDate);
      setInitialMoisture(grainBag.settings.initialMoisture);
    }
  }, [grainBag, user]);

  const removeGrainBag = () => {
    if (!grainBag) return;
    grainBagAPI
      .removeGrainBag(grainBag.key(), as)
      .then(resp => {
        openSnack("Removed Grain Bag");
        close();
        navigate("/bins");
      })
      .catch(err => {
        openSnack("Failed to remove Grain Bag");
      });
  };

  const submit = () => {
    //if a bag was passed in do an update
    if (grainBag) {
      grainBag.title = bagName;
      grainBag.settings.initialMoisture = initialMoisture;
      grainBag.settings.diameter = bagDiameterM;
      grainBag.settings.length = bagLengthM;
      grainBag.settings.customGrain = customType;
      grainBag.settings.supportedGrain = supportedGrainType;
      grainBag.settings.bushelCapacity = grainCapacity;
      grainBag.settings.grainSubtype = grainSubtype;
      grainBag.settings.fillDate = fillDate;
      grainBag.settings.bushelsPerTonne = bushelsPerTonne;
      grainBag.settings.storageType = isCustom
        ? pond.BinStorage.BIN_STORAGE_UNSUPPORTED_GRAIN
        : pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN;

      if (grainBag.bushels() !== grainBushels) {
        //grainBag.settings.currentBushels = grainBushels;
        setGrainDiff(grainBushels - grainBag.bushels());
        setGrainUpdate(true);
      } else {
        grainBagAPI
          .updateGrainBag(grainBag.key(), bagName, grainBag.settings, as)
          .then(resp => {
            openSnack("Grain Bag Updated");
            let updatedBag = clone(grainBag);
            close(updatedBag);
          })
          .catch(err => {
            openSnack("Failed to update Grain Bag");
            close();
          });
      }
    } else {
      //otherwise make a new one
      let settings = pond.GrainBagSettings.create();
      settings.initialMoisture = initialMoisture;
      settings.diameter = bagDiameterM;
      settings.length = bagLengthM;
      settings.customGrain = customType;
      settings.supportedGrain = supportedGrainType;
      settings.bushelCapacity = grainCapacity;
      settings.currentBushels = grainBushels;
      settings.grainSubtype = grainSubtype;
      settings.fillDate = fillDate;
      settings.storageType = isCustom
        ? pond.BinStorage.BIN_STORAGE_UNSUPPORTED_GRAIN
        : pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN;
      if (coordinates) {
        settings.startLocation = coordinates.start;
        settings.endLocation = coordinates.end;
      }

      grainBagAPI
        .addGrainBag(bagName, settings, as)
        .then(resp => {
          openSnack("New grain bag added");
          let newBag = GrainBag.create(
            pond.GrainBag.fromObject({
              title: bagName,
              key: resp.data.key,
              settings: settings
            })
          );
          close(newBag);
        })
        .catch(() => {
          openSnack("Failed to add new grain bag");
        });
    }
  };

  const grainBox = () => {
    if (isCustom) {
      return (
        <React.Fragment>
          <TextField
            label="Grain"
            value={customType}
            type="text"
            onChange={event => {
              setCustomType(event.target.value);
            }}
            fullWidth
            className={classes.bottomSpacing}
            variant="outlined"
          />
          <TextField
            label="Bushels Per Tonne"
            value={bushelsPerTonne}
            type="number"
            onChange={event => {
              setBushelsPerTonne(+event.target.value);
            }}
            fullWidth
            className={classes.bottomSpacing}
            variant="outlined"
          />
        </React.Fragment>
      );
    } else {
      return (
        <SearchSelect
          style={{ marginBottom: theme.spacing(1) }}
          label="Type"
          selected={selectedGrainOp}
          changeSelection={option => {
            let newGrainType = option
              ? pond.Grain[option.value as keyof typeof pond.Grain]
              : pond.Grain.GRAIN_INVALID;
            setSupportedGrainType(newGrainType);
            setBushelsPerTonne(GrainDescriber(newGrainType).bushelsPerTonne);
            setSelectedGrainOp(option);
          }}
          group
          //disabled={!canEdit}
          options={grainOptions}
        />
      );
    }
  };

  const formInvalid = () => {
    let invalid = true;
    if (bagName !== "" && grainCapacity > 0) {
      invalid = false;
    }
    return invalid;
  };

  return (
    <React.Fragment>
      <GrainTransaction
        open={grainUpdate}
        mainObject={grainBag ?? GrainBag.create()}
        grainAdjustment={grainDiff}
        close={() => {
          setGrainUpdate(false);
          setGrainDiff(0);
          //setPendingGrainAmount(undefined);
          //resetFillPercentage();
          //setGrainDiff(0);
        }}
        callback={() => {
          let updatedBag = clone(grainBag);
          close(updatedBag);
        }}
      />
      <ResponsiveDialog
        open={open}
        onClose={() => {
          close();
        }}>
        <DialogTitle>Grain Bag Settings</DialogTitle>
        <DialogContent>
          <TextField
            label="Grain Bag Name"
            fullWidth
            variant="outlined"
            value={bagName}
            onChange={e => setBagName(e.target.value)}
            className={classes.bottomSpacing}
          />
          <TextField
            label="Bag Diameter"
            InputProps={{
              endAdornment: (
                <InputAdornment position="end">
                  {user.settings.distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "ft" : "m"}
                </InputAdornment>
              )
            }}
            fullWidth
            variant="outlined"
            type="number"
            value={bagDiameterDisplay}
            onChange={e => {
              setBagDiameterDisplay(+e.target.value);
              let inMeters = +e.target.value;
              if (user.settings.distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
                //if the users preferred unit is in feet that means the value that will be saved needs to be converted to meters
                inMeters = inMeters / 3.281;
              }
              setBagDiameterM(inMeters);
            }}
            className={classes.bottomSpacing}
          />
          <TextField
            label="Bag Length"
            fullWidth
            variant="outlined"
            InputProps={{
              endAdornment: (
                <InputAdornment position="end">
                  {user.settings.distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "ft" : "m"}
                </InputAdornment>
              )
            }}
            type="number"
            value={bagLengthDispla}
            onChange={e => {
              setBagLengthDisplay(+e.target.value);
              let inMeters = +e.target.value;
              if (user.settings.distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
                //if the users preferred unit is in feet that means the value that will be saved needs to be converted to meters
                inMeters = inMeters / 3.281;
              }
              setBagLengthM(inMeters);
            }}
            className={classes.bottomSpacing}
          />
          <TextField
            fullWidth
            type="date"
            label="Fill Date"
            value={fillDate}
            InputLabelProps={{ shrink: true }}
            onChange={e => setFillDate(e.target.value)}
          />
          <Grid container alignItems="center">
            <Grid>Grain</Grid>
            <Grid>
              <Switch
                color="default"
                value={isCustom}
                checked={isCustom}
                onChange={(_, checked) => {
                  setIsCustom(checked);
                  if (checked) {
                    setSupportedGrainType(pond.Grain.GRAIN_CUSTOM);
                  } else {
                    setCustomType("");
                  }
                }}
                name="storage"
              />
            </Grid>
            <Grid>Custom</Grid>
          </Grid>
          {grainBox()}
          <TextField
            label="Grain Subtype"
            fullWidth
            variant="outlined"
            value={grainSubtype}
            onChange={e => setGrainSubtype(e.target.value)}
            className={classes.bottomSpacing}
          />
          <TextField
            label="Initial Moisture"
            fullWidth
            type="number"
            variant="outlined"
            InputProps={{
              endAdornment: <InputAdornment position="end">%</InputAdornment>
            }}
            value={initialMoisture}
            onChange={e => setInitialMoisture(+e.target.value)}
            className={classes.bottomSpacing}
          />
          <TextField
            label="Capacity"
            fullWidth
            type="number"
            variant="outlined"
            InputProps={{
              endAdornment: <InputAdornment position="end">bu</InputAdornment>
            }}
            value={grainCapacity}
            onChange={e => setGrainCapacity(+e.target.value)}
            className={classes.bottomSpacing}
          />
          <TextField
            label={
              "Current " +
              (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && bushelsPerTonne > 0
                ? "Weight"
                : "Bushels")
            }
            fullWidth
            type="number"
            variant="outlined"
            InputProps={{
              endAdornment: (
                <InputAdornment position="end">
                  {getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && bushelsPerTonne > 0
                    ? "mT"
                    : "bu"}
                </InputAdornment>
              )
            }}
            value={grainFill}
            onChange={e => {
              let bushelVal = +e.target.value;
              if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT) {
                //convert the number as a weight into the bushel value
                bushelVal = +e.target.value * (bushelsPerTonne > 0 ? bushelsPerTonne : 1);
              }
              if (bushelVal > grainCapacity) {
                bushelVal = grainCapacity;
              }
              setGrainBushels(bushelVal);
              setGrainFill(e.target.value);
            }}
            className={classes.bottomSpacing}
          />
        </DialogContent>
        <DialogActions>
          <Grid container direction="row" justifyContent="space-between">
            <Grid >
              {grainBag && (
                <Button
                  onClick={() => {
                    removeGrainBag();
                  }}
                  variant="contained"
                  style={{ background: "red" }}>
                  Delete
                </Button>
              )}
            </Grid>
            <Grid >
              <Button
                onClick={() => {
                  close();
                }}>
                Cancel
              </Button>
              <Button onClick={submit} disabled={formInvalid()} color="primary" variant="contained">
                Confirm
              </Button>
            </Grid>
          </Grid>
        </DialogActions>
      </ResponsiveDialog>
    </React.Fragment>
  );
}
