import {
  Accordion,
  AccordionDetails,
  AccordionSummary,
  Box,
  Button,
  Checkbox,
  Chip,
  darken,
  Divider,
  FormControl,
  FormControlLabel,
  Grid2 as Grid,
  ImageList as GridList,
  ImageListItem as GridListTile,
  InputLabel,
  Menu,
  MenuItem,
  Select,
  Skeleton,
  Theme,
  Typography,
  useTheme
} from "@mui/material";
import { green, yellow } from "@mui/material/colors";
import { makeStyles } from "@mui/styles";
import { ArrowBackIos, ArrowForwardIos, ExpandMore, MoreVert } from "@mui/icons-material";
//import { Skeleton } from "@material-ui/lab";
import BinInventoryChart, { GrainAmount } from "charts/BinInventoryChart";
import BinUtilizationChart from "charts/BinUtilizationChart";
//import QrCodeGenerator, { QrCodeKey } from "common/QrCodeGenerator";
import GrainDescriber, { grainName } from "grain/GrainDescriber";
import { useMobile, useWidth } from "hooks";
import { Bin } from "models";
import { pond } from "protobuf-ts/pond";
import { useBinAPI, useGlobalState } from "providers";
import React, { useEffect, useState, useCallback, SetStateAction } from "react";
import { getGrainUnit, stringToMaterialColour } from "utils";
//import BinsFansStatusTable from "./BinFansStatusTable";
import BinsList from "./BinsList";

interface Props {
  yardKey: string;
  insert?: boolean;
}

const useStyles = makeStyles((theme: Theme) => ({
    "@keyframes pulsate": {
      to: {
        boxShadow: "0 0 0 16px" + yellow["500"] + "00"
      }
    },
    green: {
      color: green["500"],
      "&:hover": {
        color: green["600"]
      }
    },
    gridList: {
      width: "100%",
      flexWrap: "nowrap",
      transform: "translateZ(0)"
    },
    pulse: {
      boxShadow: "0 0 0 0 " + yellow["500"] + "75",
      animation: "$pulsate 1.75s infinite cubic-bezier(0.66, 0.33, 0, 1)"
    },
    icon: {
      padding: 6,
      width: 36,
      height: 36,
      borderRadius: "18px",
      background: "rgba(0,0,0,0)",
      "&:hover": {
        background:
          "radial-gradient(closest-side, rgba(150, 150, 150, 0.5) 50%, rgba(150, 150, 150, 0.5))"
      }
    },
    accordion: {
      background: darken(theme.palette.background.paper, 0.4)
    }
}));

export default function BinyardDisplay(props: Props) {
  const { yardKey, insert } = props;
  const classes = useStyles();
  const binAPI = useBinAPI();
  const theme = useTheme();
  const width = useWidth();
  const isMobile = useMobile();
  const [carouselIndex, setCarouselIndex] = useState(0);
  const [binMenuAnchorEl, setBinMenuAnchorEl] = useState<Element | null>(null);
  const [{ as }] = useGlobalState();
  const maxBins = 40;
  const [binsLoading, setBinsLoading] = useState(false);
  const [expandTotal, setExpandTotal] = useState(false);
  const [displayedInventory, setDisplayedInventory] = useState<GrainAmount[]>([]);
  const [displayedFertilizer, setDisplayedFertilizer] = useState<GrainAmount[]>([]);
  const [expandUtilization, setExpandUtilization] = useState(false);
  const [expandFanTable, setExpandFanTable] = useState(false);
  const [displayGrain, setDisplayGrain] = useState(true);
  const [displayFert, setDisplayFert] = useState(false);
  const [displayEmpty, setDisplayEmpty] = useState(false);
  const [yardBins, setYardBins] = useState<Bin[]>([]);
  const [grainBins, setGrainBins] = useState<Bin[]>([]);
  const [fertBins, setFertBins] = useState<Bin[]>([]);
  const [emptyBins, setEmptyBins] = useState<Bin[]>([]);
  const [binTotal, setBinTotal] = useState(0);
  const [binMetrics, setBinMetrics] = useState<pond.BinMetrics>();
  const [contentFilter, setContentFilter] = useState<string>("");
  const [totalFanControllers, setTotalFanControllers] = useState(0);
  const [totalFanControllersOn, setTotalFanControllersOn] = useState(0);
  const [openQrGenerator, setOpenQrGenerator] = useState(false);
  const [order, setOrder] = useState<"asc" | "desc">("asc");
  const [orderBy, setOrderBy] = useState<string>("name");

  //const [qrKeyList, setQrKeyList] = useState<QrCodeKey[]>([]);

  const [scrollTranslations, setScrollTranslations] = useState({
    bins: 0,
    empty: 0,
    fertilizer: 0
  });

  const loadBins = useCallback(() => {
    if (yardKey === "") return
    //load the bins based on the yard key
    setBinsLoading(true);
    binAPI
      .listBinsAndData(maxBins, 0, "asc", "name", undefined, undefined, undefined, [yardKey], ["binyard"])
      .then(resp => {
        let yardBins: Bin[] = [];
        let grainBins: Bin[] = [];
        let fertBins: Bin[] = [];
        let emptyBins: Bin[] = [];
        //let qr: QrCodeKey[] = [];
        //set the list of bins into the yard bins
        resp.data.bins.forEach(b => {
          let bin = Bin.any(b);
          yardBins.push(bin);
          if (bin.empty()) {
            emptyBins.push(bin);
          } else if (bin.storage() === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
            fertBins.push(bin);
          } else {
            grainBins.push(bin);
          }
          //build qr keys here
          // qr.push({
          //   key: bin.key(),
          //   name: bin.name()
          // });
        });
        setYardBins(yardBins);
        setBinTotal(resp.data.total);
        //setQrKeyList(qr);
        setGrainBins(grainBins);
        if (fertBins.length > 0) {
          setDisplayFert(true);
        }
        if (emptyBins.length > 0) {
          setDisplayEmpty(true);
        }
        setFertBins(fertBins);
        setEmptyBins(emptyBins);
        setBinsLoading(false);

        let metrics = pond.BinMetrics.fromObject(resp.data.metrics ?? {});
        let inventory: GrainAmount[] = [];
        let fertInventory: GrainAmount[] = [];
        if (metrics) {
          metrics.grainInventory.forEach(grain => {
            inventory.push({
              grain: grain.grainType,
              bushelAmount: grain.bushelAmount,
              grainName: grainName(grain.grainType)
            });
          });
          metrics.customInventory.forEach(invObject => {
            if (invObject.storageType === pond.BinStorage.BIN_STORAGE_UNSUPPORTED_GRAIN) {
              inventory.push({
                grain: pond.Grain.GRAIN_CUSTOM,
                bushelAmount: invObject.amount,
                grainName: invObject.name
              });
            } else if (invObject.storageType === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
              fertInventory.push({
                grain: pond.Grain.GRAIN_CUSTOM,
                bushelAmount: invObject.amount * 35.239,
                grainName: invObject.name
              });
            }
          });
        }
        setBinMetrics(metrics);
        setDisplayedInventory(inventory);
        setDisplayedFertilizer(fertInventory);
      });
  }, [as, binAPI, yardKey]);

  const loadMoreBins = (filter: string, total?: number, offset?: number) => {
    setBinsLoading(true);
    binAPI
      .listBins(
        total ?? maxBins,
        offset ?? 0,
        order,
        orderBy,
        filter,
        as,
        undefined,
        undefined,
        [yardKey],
        ["binyard"]
      )
      .then(resp => {
        let bins = yardBins;
        //if the offset was 0 or undefined we started from the beginning so replace the yard bins with the new ones
        if (!offset || offset === 0) {
          bins = resp.data.bins.map(b => Bin.any(b));
          //else append the new ones on to the end of the existing yard bins
        } else {
          bins = bins.concat(resp.data.bins.map(b => Bin.any(b)));
        }
        //loop through the new list of bins setting the bins into the correct sections
        let grainBins: Bin[] = [];
        let fertBins: Bin[] = [];
        let emptyBins: Bin[] = [];
        //let qr: QrCodeKey[] = [];
        //set the list of bins into the yard bins
        resp.data.bins.forEach(b => {
          let bin = Bin.any(b);
          yardBins.push(bin);
          if (bin.empty()) {
            emptyBins.push(bin);
          } else if (bin.storage() === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
            fertBins.push(bin);
          } else {
            grainBins.push(bin);
          }
          //build qr keys here
          // qr.push({
          //   key: bin.key(),
          //   name: bin.name()
          // });
        });
        setYardBins(bins);
        setBinTotal(resp.data.total);
        //setQrKeyList(qr);
        setGrainBins(grainBins);
        if (fertBins.length > 0) {
          setDisplayFert(true);
        }
        if (emptyBins.length > 0) {
          setDisplayEmpty(true);
        }
        setFertBins(fertBins);
        setEmptyBins(emptyBins);
        setBinsLoading(false);
      });
  };

  useEffect(() => {
    loadBins();
  }, [yardKey, loadBins]);

  useEffect(() => {
    let ebt = sessionStorage.getItem("expandBinTotal");
    if (ebt === "true") {
      setExpandTotal(true);
    } else {
      setExpandTotal(false);
    }

    let ebu = sessionStorage.getItem("expandBinUtilization");
    if (ebu === "true") {
      setExpandUtilization(true);
    } else {
      setExpandUtilization(false);
    }

    let fanTable = sessionStorage.getItem("expandFanTable");
    if (fanTable === "true") {
      setExpandFanTable(true);
    } else {
      setExpandFanTable(false);
    }
  }, []);

  const duplicateBin = (bin: Bin) => {
    binAPI.addBin(bin.settings, as).then(resp => {
      loadBins();
    });
  };

  const binsContent = () => {
    if (!binsLoading && binTotal === 0) {
      return (
        <Box textAlign="center" marginTop={1}>
          <Typography variant="subtitle1">No bins found</Typography>
          <Typography variant="body1" color="textSecondary">
            Create a bin and it will appear here
          </Typography>
        </Box>
      );
    }

    return (
      <React.Fragment>
        <Grid container>
          {displayGrain && (
            <React.Fragment>
              <Grid size={12}>
                <Divider />
              </Grid>
              <Grid size={12}>
                <BinsList
                  gridView
                  valDisplay="average"
                  bins={grainBins}
                  duplicateBin={duplicateBin}
                  title={"Grain Bins"}
                />
              </Grid>
            </React.Fragment>
          )}
          {displayFert && (
            <React.Fragment>
              <Grid size={12}>
                <Divider />
              </Grid>
              <Grid size={12}>
                <BinsList
                  gridView
                  valDisplay="average"
                  bins={fertBins}
                  duplicateBin={duplicateBin}
                  title={"Fertilizer Bins"}
                />
              </Grid>
            </React.Fragment>
          )}
          {displayEmpty && (
            <React.Fragment>
              <Grid size={12}>
                <Divider />
              </Grid>
              <Grid size={12}>
                <BinsList
                  gridView
                  valDisplay="average"
                  bins={emptyBins}
                  duplicateBin={duplicateBin}
                  title={"Empty Bins"}
                  // loadMore={newTranslation => {
                  //   //only triggered in the scroll view so this will never trigger in grid view
                  //   if (yardBins.length < binTotal) {
                  //     loadMoreBins(contentFilter);
                  //     setScrollTranslations({ ...scrollTranslations, empty: newTranslation });
                  //   }
                  // }}
                />
              </Grid>
            </React.Fragment>
          )}
        </Grid>
      </React.Fragment>
    );
  };

  const binsHeader = () => {
    return (
      <Menu
        id="yardMenu"
        anchorEl={binMenuAnchorEl ? binMenuAnchorEl : null}
        open={binMenuAnchorEl !== null}
        onClose={() => {
          setBinMenuAnchorEl(null);
        }}
        disableAutoFocusItem>
        <MenuItem>
          <FormControl style={{ marginLeft: theme.spacing(2) }}>
            <InputLabel id="demo-simple-select-label">Order</InputLabel>
            <Select
              labelId="demo-simple-select-label"
              id="demo-simple-select"
              value={order}
              onChange={event => setOrder(event.target.value as SetStateAction<"asc" | "desc">)}>
              <MenuItem value={"asc"}>Ascending</MenuItem>
              <MenuItem value={"desc"}>Descending</MenuItem>
            </Select>
          </FormControl>
        </MenuItem>
        <MenuItem>
          <FormControl style={{ marginLeft: theme.spacing(2) }}>
            <InputLabel id="demo-simple-select-label">Order By</InputLabel>
            <Select
              labelId="demo-simple-select-label"
              id="demo-simple-select"
              value={orderBy}
              onChange={event => setOrderBy(event.target.value as SetStateAction<string>)}>
              <MenuItem value={"name"}>Name</MenuItem>
              <MenuItem value={"timestamp"}>Timestamp</MenuItem>
            </Select>
          </FormControl>
        </MenuItem>
        <Divider />
        <MenuItem>
          <FormControlLabel
            control={
              <Checkbox
                checked={displayGrain}
                onChange={(e, checked) => {
                  setDisplayGrain(checked);
                }}
              />
            }
            label={<Typography>Grain</Typography>}
          />
        </MenuItem>
        <MenuItem>
          <FormControlLabel
            control={
              <Checkbox
                checked={displayFert}
                onChange={(e, checked) => {
                  setDisplayFert(checked);
                }}
              />
            }
            label={<Typography>Fertilizer</Typography>}
          />
        </MenuItem>
        <MenuItem>
          <FormControlLabel
            control={
              <Checkbox
                checked={displayEmpty}
                onChange={(e, checked) => {
                  setDisplayEmpty(checked);
                }}
              />
            }
            label={<Typography>Empty Bins</Typography>}
          />
        </MenuItem>
        {/* <MenuItem
          onClick={() => {
            setOpenQrGenerator(true);
          }}>
          <Typography>Generate QR Codes</Typography>
        </MenuItem> */}
      </Menu>
    );
  };

  const binsByGrainType = () => {
    return (
      <Box width={1} marginBottom={1}>
        <Grid
          container
          direction="row"
          alignContent="center"
          alignItems="center">
          <Grid>
            <Box display="flex" paddingY={1} alignContent="center" alignItems="center">
              <Typography variant="h6" style={{ fontWeight: 650 }}>
                Bins - ({yardBins.length} of {binTotal})
              </Typography>
              {contentFilter && (
                <Box marginLeft={1}>
                  <Chip
                    size="small"
                    onDelete={() => {
                      setContentFilter("");
                      loadMoreBins("");
                    }}
                    label={contentFilter}
                  />
                </Box>
              )}
              {yardBins.length < binTotal && (
                <Button
                  style={{ marginLeft: 10 }}
                  variant="contained"
                  color="primary"
                  onClick={() => {
                    loadMoreBins(contentFilter, 0, yardBins.length);
                  }}>
                  Load All
                </Button>
              )}
            </Box>
          </Grid>
          <Grid>
            <MoreVert
              className={classes.icon}
              onClick={event => {
                let target = event.currentTarget;
                setBinMenuAnchorEl(target);
              }}
            />
          </Grid>
        </Grid>
        {binsLoading ? <Skeleton variant="rectangular" height="200px" /> : binsContent()}
        {binsHeader()}
      </Box>
    );
  };

  const desktopInventory = () => {
    return (
      <React.Fragment>
        <Grid container direction="row" alignContent="center" alignItems="center">
          <Grid style={{ height: "200px" }} size={6}>
            <BinInventoryChart
              customLabel="Grain"
              inventory={displayedInventory}
              onClick={(grain: pond.Grain, grainName: string) => {
                let filter = "";
                if (grain !== pond.Grain.GRAIN_NONE && grain !== pond.Grain.GRAIN_CUSTOM) {
                  filter = pond.Grain[grain];
                } else {
                  filter = grainName;
                }
                setContentFilter(filter);
                loadMoreBins(filter);
              }}
              //activeGrain={grainFilter}
            />
          </Grid>
          <Grid style={{ height: "200px" }} size={6}>
            <BinInventoryChart
              customLabel="Fertilizer"
              inventory={displayedFertilizer}
              onClick={(grain: pond.Grain, grainName: string) => {
                let filter = "";
                if (grain !== pond.Grain.GRAIN_NONE && grain !== pond.Grain.GRAIN_CUSTOM) {
                  filter = pond.Grain[grain];
                } else {
                  filter = grainName;
                }
                setContentFilter(filter);
                loadMoreBins(filter);
              }}
              customUnit={"L"}
              //activeGrain={grainFilter}
            />
          </Grid>
        </Grid>
      </React.Fragment>
    );
  };

  const mobileViewCarousel = () => {
    let length = 2;
    let charts: JSX.Element[] = [
      <BinInventoryChart
        customLabel="Grain"
        inventory={displayedInventory}
        onClick={(grain: pond.Grain, grainName: string) => {
          let filter = "";
          if (grain !== pond.Grain.GRAIN_NONE && grain !== pond.Grain.GRAIN_CUSTOM) {
            filter = pond.Grain[grain];
          } else {
            filter = grainName;
          }
          setContentFilter(filter);
          loadMoreBins(filter);
        }}
        //activeGrain={grainFilter}
      />,
      <BinInventoryChart
        customLabel="Fertilizer"
        inventory={displayedFertilizer}
        onClick={(grain: pond.Grain, grainName: string) => {
          let filter = "";
          if (grain !== pond.Grain.GRAIN_NONE && grain !== pond.Grain.GRAIN_CUSTOM) {
            filter = pond.Grain[grain];
          } else {
            filter = grainName;
          }
          setContentFilter(filter);
          loadMoreBins(filter);
        }}
        customUnit={"L"}
        //activeGrain={grainFilter}
      />
    ];
    return (
      <React.Fragment>
        <Grid container direction="row" alignContent="center" alignItems="center">
          <Grid size={2}>
            <Button
              style={{ height: 160 }}
              onClick={() => {
                const newIndex = carouselIndex - 1;
                setCarouselIndex(newIndex < 0 ? length - 1 : newIndex);
              }}>
              <ArrowBackIos />
            </Button>
          </Grid>
          <Grid size={8}>
            <Box height={"180px"} flexDirection="row" display="flex">
              {charts[carouselIndex]}
            </Box>
          </Grid>
          <Grid size={2}>
            <Button
              style={{ height: 160 }}
              onClick={() => {
                const newIndex = carouselIndex + 1;
                setCarouselIndex(newIndex >= length ? 0 : newIndex);
              }}>
              <ArrowForwardIos />
            </Button>
          </Grid>
        </Grid>
      </React.Fragment>
    );
  };

  const totalInventory = () => {
    return (
      <Accordion
        className={classes.accordion}
        expanded={expandTotal}
        onChange={(_, expanded) => {
          setExpandTotal(expanded);
          sessionStorage.setItem("expandBinTotal", expanded.toString());
        }}>
        <AccordionSummary expandIcon={<ExpandMore />}>
          <Typography variant="h6" style={{ fontWeight: 650 }}>
            Total Inventory
          </Typography>
        </AccordionSummary>
        <AccordionDetails>
          {isMobile || insert ? mobileViewCarousel() : desktopInventory()}
        </AccordionDetails>
      </Accordion>
    );
  };

  const binUtilizationList = () => {
    const hasInventory = binMetrics && binMetrics.grainInventory.length > 0;
    const useWeight = getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT;
    return (
      <Accordion
        className={classes.accordion}
        style={{ marginTop: 5 }}
        expanded={expandUtilization}
        onChange={(_, expanded) => {
          setExpandUtilization(expanded);
          sessionStorage.setItem("expandBinUtilization", expanded.toString());
        }}>
        <AccordionSummary expandIcon={<ExpandMore />}>
          <Typography variant="h6" style={{ fontWeight: 650 }}>
            Bin Utilization
          </Typography>
        </AccordionSummary>
        <AccordionDetails>
          {hasInventory ? (
            <Box width={"100%"}>
              <Typography variant="caption" color="textSecondary">
                Click a chart to filter bins by grain
              </Typography>
              <GridList
                className={classes.gridList}
                cols={
                  props.insert && !isMobile
                    ? 3
                    : width === "xs"
                    ? 3
                    : width === "sm"
                    ? 5
                    : width === "md"
                    ? 6
                    : width === "lg"
                    ? 7
                    : 8
                }>
                {binMetrics &&
                  binMetrics.grainInventory.map((inv, key) => (
                    <GridListTile key={key}>
                      <BinUtilizationChart
                        grain={inv.grainType}
                        customUnit={useWeight ? " mT" : " bu"}
                        bushelAmount={
                          useWeight
                            ? inv.bushelAmount / GrainDescriber(inv.grainType).bushelsPerTonne
                            : inv.bushelAmount
                        }
                        bushelCapacity={
                          useWeight
                            ? inv.bushelCapacity / GrainDescriber(inv.grainType).bushelsPerTonne
                            : inv.bushelCapacity
                        }
                        onClick={() => {
                          setContentFilter(pond.Grain[inv.grainType]);
                          loadMoreBins(pond.Grain[inv.grainType]);
                        }}
                        grainActive={contentFilter === pond.Grain[inv.grainType]}
                      />
                    </GridListTile>
                  ))}
                {binMetrics &&
                  binMetrics.customInventory.map((inv, key) => {
                    //default to bushel values
                    let amount = inv.amount;
                    let cap = inv.capacity;
                    let unit = " bu";
                    if (inv.storageType === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
                      amount = amount * 35.239;
                      cap = cap * 35.239;
                      unit = " L";
                    }
                    if (useWeight && inv.bushelsPerTonne > 1) {
                      amount = amount / inv.bushelsPerTonne;
                      cap = cap / inv.bushelsPerTonne;
                      unit = " mT";
                    }

                    return (
                      <GridListTile key={key}>
                        <BinUtilizationChart
                          grain={pond.Grain.GRAIN_CUSTOM}
                          bushelAmount={amount}
                          bushelCapacity={cap}
                          customUnit={unit}
                          onClick={() => {
                            setContentFilter(inv.name);
                            loadMoreBins(inv.name);
                          }}
                          grainActive={contentFilter === inv.name}
                          customLabel={inv.name}
                          customColour={stringToMaterialColour(inv.name)}
                        />
                      </GridListTile>
                    );
                  })}
              </GridList>
            </Box>
          ) : (
            <Typography color="textSecondary" style={{ margin: "2rem", marginTop: "0rem" }}>
              No active bins
            </Typography>
          )}
        </AccordionDetails>
      </Accordion>
    );
  };

  const binFanTable = () => {
    return (
      <Accordion
        className={classes.accordion}
        expanded={expandFanTable}
        style={{ marginTop: 5 }}
        onChange={(_, expanded) => {
          setExpandFanTable(expanded);
          sessionStorage.setItem("expandFanTable", expanded.toString());
        }}>
        <AccordionSummary expandIcon={<ExpandMore />}>
          <Typography variant="h6" style={{ fontWeight: 650 }}>
            Fan Status{" "}
            {totalFanControllers > 0 && !isMobile
              ? " - " + totalFanControllersOn + " of " + totalFanControllers + " controllers on"
              : ""}
          </Typography>
        </AccordionSummary>
        <AccordionDetails>
          {/* <BinsFansStatusTable
            bins={yardBins}
            isLoading={binsLoading}
            getControllerInfo={(total, on) => {
              setTotalFanControllers(total);
              setTotalFanControllersOn(on);
            }}
          /> */}
        </AccordionDetails>
      </Accordion>
    );
  };

  return (
    <Box height={1}>
      <Box paddingY={0.5} paddingX={1}>
        <Grid container>
          <Grid size={12}>
            {binsByGrainType()}
          </Grid>
          <Grid size={12}>
            {binsLoading ? <Skeleton variant="rectangular" height="200px" /> : totalInventory()}
          </Grid>
          <Grid size={12}>
            <Divider />
          </Grid>
          <Grid size={12}>
            {binsLoading ? <Skeleton variant="rectangular" height="200px" /> : binUtilizationList()}
          </Grid>
          <Grid size={12}>
            <Divider />
          </Grid>
          <Grid size={12}>
            {binsLoading ? <Skeleton variant="rectangular" height="200px" /> : binFanTable()}
          </Grid>
          <Grid size={12}>
            <Divider />
          </Grid>
        </Grid>
      </Box>
      {/* <QrCodeGenerator
        open={openQrGenerator}
        close={() => {
          setOpenQrGenerator(false);
        }}
        keyList={qrKeyList}
        requiredUrlAffix={"bins"}
      /> */}
    </Box>
  );
}
