import {
  AppBar,
  Button,
  CircularProgress,
  Dialog,
  DialogActions,
  DialogContent,
  DialogContentText,
  DialogTitle,
  Grid2 as Grid,
  Grid2,
  ListItemIcon,
  ListItemText,
  Menu,
  MenuItem,
  Tab,
  TextField,
  Theme,
  Tooltip,
  Typography,
  useTheme
} from "@mui/material";
import { pond } from "protobuf-ts/pond";
import {
  useBinYardAPI,
  useSnackbar,
  usePermissionAPI,
  useBinAPI,
  useGlobalState
} from "providers";
import React, { useEffect, useState } from "react";
import AddIcon from "@mui/icons-material/LibraryAdd";
import ResponsiveDialog from "common/ResponsiveDialog";
import { MoreVert, Search } from "@mui/icons-material";
import DeleteIcon from "@mui/icons-material/Delete";
import RemoveSelfIcon from "@mui/icons-material/ExitToApp";
import KeyboardArrowLeftIcon from "@mui/icons-material/KeyboardArrowLeft";
import KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight";
import ObjectUsersIcon from "@mui/icons-material/SupervisedUserCircle";
import EditIcon from "@mui/icons-material/Edit";
import ShareIcon from "@mui/icons-material/Share";
import { red, blue, green } from "@mui/material/colors";
import { openSnackbar } from "providers/Snackbar";
import { binScope, binYardScope } from "models/Scope";
import ShareObject from "user/ShareObject";
import { Bin, Team, User } from "models";
import { Dictionary, transform } from "lodash";
import ObjectUsers from "user/ObjectUsers";
import ObjectTeams from "teams/ObjectTeams";
import { GrainBag } from "models/GrainBag";
import { makeStyles } from "@mui/styles";
import DraggableTabs from "common/DraggableTabs";
import CancelSubmit from "common/CancelSubmit";

const parentTab = {
  "&": {
    margin: "0px",
    marginTop: "4px",
    marginLeft: "4px",
    animationDuration: "10s",
    transform: "0.3s ease-in-out",
    // transition: transform 0.3s ease-in-out,
    // background: "rgba(150, 150, 150, 0)",

    borderRadius: "-5px",
    borderTopLeftRadius: "6px",
    borderTopRightRadius: "6px"
  },
  "&:hover": {
    background: "linear-gradient(rgba(150, 150, 150, 0.2), rgba(150, 150, 150, 0))"
  }
};

const useStyles = makeStyles((theme: Theme) => {
  return ({
    red: {
      marginRight: 0,
      paddingRight: 0,
      color: red["500"],
      "&:hover": {
        color: red["600"]
      }
    },
    blue: {
      marginRight: 0,
      paddingRight: 0,
      color: blue["500"],
      "&:hover": {
        color: blue["600"]
      }
    },
    green: {
      marginRight: 0,
      paddingRight: 0,
      color: green["500"],
      "&:hover": {
        color: green["600"]
      }
    },
    searchTab: {
      ...parentTab,
      width: theme.spacing(8),
      minWidth: theme.spacing(8),
      left: 0,
      height: "100%",
      // background: theme.palette.background.paper
    },
    searchTabExpanded: {
      ...parentTab,
      width: theme.spacing(30),
      minWidth: theme.spacing(30),
      left: 0,
      height: "100%",
      // background: theme.palette.background.paper
    },
    tab: {
      ...parentTab,
      color: theme.palette.text.primary,
      transform: "0.3s ease-in-out",
    },
    smallTab: {
      ...parentTab,
      width: theme.spacing(8),
      minWidth: theme.spacing(8),
      transform: "0.3s ease-in-out",
      // background: theme.palette.background.paper
    },
    selectedTab: {
      borderRadius: "-5px",
      borderTopLeftRadius: "6px",
      borderTopRightRadius: "6px",
      background: theme.palette.background.default,
      fontWeight: 1000,
      transform: "0.3s ease-in-out",
          // "linear-gradient(rgba(150, 150, 150, 0.3)," 
          // + theme.palette.background.default + " 80%)"
      "&:hover": {
        background:
          "linear-gradient(rgba(150, 150, 150, 0.3)," + theme.palette.background.default + " 80%)"
      }
    },
    icon: {
      display: "flex",
      position: "absolute",
      right: 0,
      top: 6,
      padding: 6,
      marginRight: "2px",
      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))"
      // }
    },
    tabText: {
      position: "absolute",
      left: theme.spacing(2),
      color: "transparent",
      textAlign: "left",
      marginTop: "auto",
      width: "80%",
      backgroundImage: "linear-gradient(to right, white 70%, rgba(200, 200, 200, 0) 87.5%)",
      backgroundClip: "text",
      WebkitBackgroundClip: "text",
      overflowX: "hidden",
      whiteSpace: "nowrap",
      top: "auto",
      bottom: "auto"
    }
  });
});

interface Props {
  setYardFilter: React.Dispatch<React.SetStateAction<string>>;
  loadBins: () => void;
  loadYards: (search?: string, limit?: number, offset?: number) => void;
  yardsLoading: boolean;
  tab?: number;
  yards?: pond.BinYardSettings[];
  yardPerms?: Dictionary<pond.Permission[]>;
  showTabs?: boolean;
  bins: Bin[];
  grainBags: GrainBag[];
  setShowing: (showing: "all" | "bins" | "bags") => void;
}

export default function BinYard(props: Props) {
  const { setYardFilter, loadBins, loadYards, /*gainBags,*/ setShowing, yardsLoading } = props;
  const binYardAPI = useBinYardAPI();
  const binAPI = useBinAPI();
  const [tab, setTab] = useState<number>(props.tab ? props.tab : 1);
  const [showAddYard, setShowAddYard] = useState<boolean>(false);
  const [addYardName, setAddYardName] = useState<string>("");
  const [addYardDescription, setAddYardDescription] = useState<string>("");
  const [binYards, setBinYards] = useState<pond.BinYardSettings[]>(props.yards ? props.yards : []);
  const [menuAnchorEl, setMenuAnchorEl] = useState<Element | null>(null);
  const [yardIndex, setYardIndex] = useState<number>(0);
  const [tabClick, setTabClick] = useState<boolean>(true);
  const [shareDialog, setShareDialog] = useState<boolean>(false);
  const [userDialog, setUserDialog] = useState<boolean>(false);
  const [teamDialog, setTeamDialog] = useState<boolean>(false);
  const [openUpdateYardDialog, setOpenUpdateYardDialog] = useState(false);
  const { error, warning, success } = useSnackbar();
  const theme = useTheme();
  const classes = useStyles();
  const [leaveYardDialogOpen, setLeaveYardDialogOpen] = useState<boolean>(false);
  const permissionAPI = usePermissionAPI();
  const [leaving, setLeaving] = useState<boolean>(false);
  const [yardPermissions, setYardPermissions] = useState<Dictionary<pond.Permission[]>>({});
  const [searchSelected, setSearchSelected] = useState(false);
  const [{ user, as }] = useGlobalState();
  const [addingYard, setAddingYard] = useState(false)

  useEffect(() => {
    if (props.yards && props.yardPerms) {
      setBinYards(props.yards);
      setYardPermissions(props.yardPerms);
      return;
    }
  }, [props.yards, props.yardPerms]);

  const tabChange = (i: number) => {
    if (tab === i) return;
    if (i === binYards.length + 2) return;
    if (tabClick !== true) return;
    setTab(i);
    setYardFilter("");
    if (i > 1 && i <= binYards.length + 1) {
      setYardFilter(binYards[i - 2].key);
    }
  };

  const submitYard = () => {
    if (addingYard) return
    setAddingYard(true)
    let newBinYard = pond.BinYardSettings.create();
    newBinYard.name = addYardName;
    newBinYard.description = addYardDescription;
    newBinYard.owner = user.id();
    binYardAPI
      .addBinYard(newBinYard, as)
      .then(resp => {
        // loadYards();
        let newYards = [...binYards]
        newYards.push(newBinYard)
        setBinYards(newYards)
        setShowAddYard(false);
        newBinYard.key = resp.data.yard

        let newYardPermissions: Dictionary<pond.Permission[]> = { ...yardPermissions };
        newYardPermissions[newBinYard.key] = [
          pond.Permission.PERMISSION_READ, 
          pond.Permission.PERMISSION_SHARE,
          pond.Permission.PERMISSION_USERS,
          pond.Permission.PERMISSION_WRITE
        ];
        setYardPermissions(newYardPermissions)
        openSnackbar("success", "Bin Yard created :)");
      })
      .catch(_err => {
        error("Could not add bin yard");
      }).finally(() => {
        setAddingYard(false)
      });
  };

  const updateYard = () => {
    let newBinYard = binYards[yardIndex];
    newBinYard.name = addYardName;
    newBinYard.description = addYardDescription;
    binYardAPI
      .updateBinYard(newBinYard.key, newBinYard, undefined, as)
      .then(_resp => {
        loadYards();
        openSnackbar("success", "Bin Yard updated");
        setOpenUpdateYardDialog(false);
      })
      .catch(_err => {
        error("Could not update bin yard");
        setOpenUpdateYardDialog(false);
      });
  };

  const yardForm = () => {
    return (
      <DialogContent>
        <DialogContentText style={{ paddingBottom: theme.spacing(0) }}>
          Bin yards allow you to organise your bins by tab. Bins created while a bin yard tab is
          opened will automatically be added to that bin yard. You may also choose a yard for a bin
          in the bin settings page.
        </DialogContentText>
        <TextField
          label={"Yard Name"}
          value={addYardName}
          onChange={event => setAddYardName(event.target.value)}
          style={{ marginTop: theme.spacing(0) }}
          fullWidth
          variant="outlined"
        />
        <DialogContentText
          style={{ paddingBottom: theme.spacing(0), paddingTop: theme.spacing(3) }}>
          Bin yard description (optional):
        </DialogContentText>
        <TextField
          label={"Description"}
          value={addYardDescription}
          onChange={event => setAddYardDescription(event.target.value)}
          style={{ marginTop: theme.spacing(0) }}
          fullWidth
          variant="outlined"
        />
      </DialogContent>
    );
  };

  const addYardDialog = () => {
    return (
      <ResponsiveDialog open={showAddYard} onClose={() => setShowAddYard(false)}>
        <DialogTitle>Create New Bin Yard</DialogTitle>
        {yardForm()}
        <DialogActions>
          <CancelSubmit
            submitDisabled={addingYard}
            onCancel={() => setShowAddYard(false)}
            onSubmit={submitYard}
          />
        </DialogActions>
      </ResponsiveDialog>
    );
  };

  const updateYardDialog = () => {
    return (
      <ResponsiveDialog open={openUpdateYardDialog} onClose={() => setOpenUpdateYardDialog(false)}>
        <DialogTitle>Update Bin Yard</DialogTitle>
        {yardForm()}
        <DialogActions>
          <Button
            onClick={() => {
              setOpenUpdateYardDialog(false);
            }}
            color="primary">
            Cancel
          </Button>
          <Button onClick={updateYard} color="primary">
            Update
          </Button>
        </DialogActions>
      </ResponsiveDialog>
    );
  };

  const deleteYard = (index: number) => {
    let newBinYards = binYards;
    binYardAPI
      .removeBinYard(binYards[index].key, as)
      .then(_resp => {
        newBinYards.splice(index, 1);
        if (index + 1 === tab) {
          tabChange(0);
        } else if (index + 1 < tab) {
          tabChange(tab - 1);
        }
        setBinYards([...newBinYards]);
      })
      .catch(_err => {
        error("Failed to delete bin yard");
      });
  };

  const openShareDialog = () => {
    setShareDialog(true);
  };

  const leaveYardDialog = () => {
    if (!binYards[yardIndex]) return;
    let label = binYards[yardIndex].name;
    return (
      <Dialog
        open={leaveYardDialogOpen}
        onClose={() => setLeaveYardDialogOpen(false)}
        aria-labelledby="remove-self-from-object">
        <DialogTitle id="remove-self-from-object">{"Leave " + label + "?"}</DialogTitle>
        <DialogContent>
          <Typography color="textSecondary" align="left" variant="subtitle1">
            You will no longer be able to access {label}. You will also lose access to all bins in{" "}
            {label} that you do not own.
          </Typography>
        </DialogContent>
        <DialogActions>
          <Button onClick={() => setLeaveYardDialogOpen(false)} color="primary">
            Cancel
          </Button>
          <Button onClick={leaveYard} color="primary" autoFocus>
            Leave
          </Button>
        </DialogActions>
      </Dialog>
    );
  };

  const leaveYard = () => {
    updateYardPermissions();
  };

  const updateYardPermissions = (users?: User[] | Team[]) => {
    if (leaving) return;
    setLeaving(true);
    let binSuccess = true;
    setLeaving(true);
    binAPI.listBins(150, 0, "asc", "name", binYards[yardIndex].key).then(resp => {
      resp.data.bins.forEach(bin => {
        if (bin.settings) {
          let scope = binScope(bin.settings?.key);
          users = users
            ? users
            : [
                User.create(
                  pond.User.create({
                    settings: pond.UserSettings.create({
                      id: user.id()
                    }),
                    permissions: []
                  })
                )
              ];
          permissionAPI.updatePermissions(scope, users).catch(_ => {
            binSuccess = false;
          });
        }
      });
    });
    if (binSuccess) {
      let scope = binYardScope(binYards[yardIndex].key);
      let label = binYards[yardIndex].name;
      users = users
        ? users
        : [
            User.create(
              pond.User.create({
                settings: pond.UserSettings.create({
                  id: user.id()
                }),
                permissions: []
              })
            )
          ];
      permissionAPI
        .updatePermissions(scope, users)
        .then((_response: any) => {
          success("Successfully updated permissions for " + label);
          setLeaveYardDialogOpen(false);
          loadYards();
          loadBins();
          tabChange(0);
        })
        .catch((err: any) => {
          err.response.data.error
            ? warning(err.response.data.error)
            : error("Error occured when updating permissions for " + label);
          setLeaveYardDialogOpen(false);
        })
        .finally(() => {
          setLeaving(false);
        });
    } else {
      error("Error updating permissions on one or more bins");
      setLeaving(false);
    }
  };

  const yardMenu = () => {
    let permissions: pond.Permission[] = [];
    if (binYards[yardIndex] === undefined) return;
    if (yardPermissions[binYards[yardIndex].key] !== undefined) {
      permissions = yardPermissions[binYards[yardIndex].key];
    }
    return (
      <Menu
        id="yardMenu"
        anchorEl={menuAnchorEl ? menuAnchorEl : null}
        open={menuAnchorEl !== null}
        onClose={() => {
          setMenuAnchorEl(null);
        }}
        disableAutoFocusItem>
        {permissions.includes(pond.Permission.PERMISSION_WRITE) && (
          <MenuItem
            onClick={() => {
              setOpenUpdateYardDialog(true);
              setAddYardName(binYards[yardIndex].name);
              setAddYardDescription(binYards[yardIndex].description);
              setMenuAnchorEl(null);
            }}
            aria-label="Edit Yard"
            dense>
            <ListItemIcon>
              <EditIcon className={classes.green} />
            </ListItemIcon>
            <ListItemText secondary="Edit Yard" />
          </MenuItem>
        )}
        {permissions.includes(pond.Permission.PERMISSION_SHARE) && (
          <MenuItem
            onClick={() => {
              setMenuAnchorEl(null);
              openShareDialog();
            }}
            aria-label="Share Yard"
            dense>
            <ListItemIcon>
              <ShareIcon className={classes.blue} />
            </ListItemIcon>
            <ListItemText secondary="Share Yard" />
          </MenuItem>
        )}
        {/* <MenuItem
          onClick={() => {
            moveLeft(yardIndex);
            setMenuAnchorEl(null);
          }}
          aria-label="Move Left"
          dense>
          <ListItemIcon>
            <KeyboardArrowLeftIcon />
          </ListItemIcon>
          <ListItemText secondary="Move Left" />
        </MenuItem>
        <MenuItem
          onClick={() => {
            moveRight(yardIndex);
            setMenuAnchorEl(null);
          }}
          aria-label="Move Right"
          dense>
          <ListItemIcon>
            <KeyboardArrowRightIcon />
          </ListItemIcon>
          <ListItemText secondary="Move Right" />
        </MenuItem> */}
        {permissions.includes(pond.Permission.PERMISSION_USERS) && (
          <MenuItem
            onClick={() => {
              setUserDialog(true);
              setMenuAnchorEl(null);
            }}
            aria-label="Users"
            dense>
            <ListItemIcon>
              <ObjectUsersIcon />
            </ListItemIcon>
            <ListItemText secondary="Users" />
          </MenuItem>
        )}
        {permissions.includes(pond.Permission.PERMISSION_USERS) && (
          <MenuItem
            onClick={() => {
              setTeamDialog(true);
              setMenuAnchorEl(null);
            }}
            aria-label="Teams"
            dense>
            <ListItemIcon>
              <ObjectUsersIcon />
            </ListItemIcon>
            <ListItemText secondary="Teams" />
          </MenuItem>
        )}
        {permissions.includes(pond.Permission.PERMISSION_SHARE) &&
        permissions.includes(pond.Permission.PERMISSION_READ) &&
        permissions.includes(pond.Permission.PERMISSION_USERS) &&
        permissions.includes(pond.Permission.PERMISSION_WRITE) ? (
          <MenuItem
            onClick={() => {
              deleteYard(yardIndex);
              setMenuAnchorEl(null);
            }}
            aria-label="Delete Yard"
            dense>
            <ListItemIcon>
              <DeleteIcon className={classes.red} />
            </ListItemIcon>
            <ListItemText secondary="Delete Yard" />
          </MenuItem>
        ) : (
          <MenuItem
            onClick={() => {
              setLeaveYardDialogOpen(true);
              setMenuAnchorEl(null);
            }}
            aria-label="Leave Yard"
            dense>
            <ListItemIcon>
              <RemoveSelfIcon className={classes.red} />
            </ListItemIcon>
            <ListItemText secondary="Leave Yard" />
          </MenuItem>
        )}
      </Menu>
    );
  };

  let permissions: pond.Permission[] = [];
  if (binYards[yardIndex] !== undefined) {
    permissions = yardPermissions[binYards[yardIndex].key] || [];
  }
  return (
    <AppBar
      position="sticky"
      elevation={0}
      style={props.showTabs ? {} : { visibility: "hidden", height: 0 }}>
      {addYardDialog()}
      {updateYardDialog()}
      {yardMenu()}
      {leaveYardDialog()}
      {binYards[yardIndex] && (
        <ShareObject
          scope={binYardScope(binYards[yardIndex].key)}
          label={binYards[yardIndex].name}
          permissions={permissions}
          isDialogOpen={shareDialog}
          closeDialogCallback={() => setShareDialog(false)}
        />
      )}
      {binYards[yardIndex] && (
        <ObjectUsers
          scope={binYardScope(binYards[yardIndex].key)}
          label={binYards[yardIndex].name}
          permissions={permissions}
          isDialogOpen={userDialog}
          closeDialogCallback={() => setUserDialog(false)}
          refreshCallback={() => {}}
          userCallback={updateYardPermissions}
          dialog={
            "Updating a user's permissions for this bin yard will update the same permissions for all corresponding bins."
          }
        />
      )}
      {binYards[yardIndex] && (
        <ObjectTeams
          scope={binYardScope(binYards[yardIndex].key)}
          label={binYards[yardIndex].name}
          permissions={permissions}
          isDialogOpen={teamDialog}
          closeDialogCallback={() => setTeamDialog(false)}
          refreshCallback={() => {}}
          userCallback={updateYardPermissions}
          dialog={
            "Updating a user's permissions for this bin yard will update the same permissions for all corresponding bins."
          }
        />
      )}
      <DraggableTabs
        variant="scrollable"
        scrollButtons="auto"
        sx={{ background: theme.palette.background.paper }}
        value={tab}
        TabIndicatorProps={{ style: { background: "rgba(0,0,0,0)" } }}
        onChange={(_, newValue) => {
          // if (+newValue > 0) {
            tabChange(newValue);
          // }
        }}
        startNode={
          <>
            <Tab
              className={searchSelected ? classes.searchTabExpanded : classes.searchTab}
              disableTouchRipple
              disableFocusRipple
              draggable={false}
              label={
                <Grid container direction="row" wrap="nowrap" spacing={2}>
                  <Grid>{yardsLoading ? <CircularProgress size={20} /> : <Search />}</Grid>
                  {searchSelected && (
                    <Grid>
                      <TextField
                        onChange={e => {
                          loadYards(e.target.value);
                        }}
                      />
                    </Grid>
                  )}
                </Grid>
              }
              onClick={_e => {
                setSearchSelected(true);
              }}
            />
            <Tab
              classes={{ root: classes.smallTab, selected: classes.selectedTab }}
              style={{ marginLeft: theme.spacing(1) }}
              label="All"
              draggable={false}
              disableTouchRipple={true}
              onClick={() => {
                setShowing("all");
              }}
            />
          </>
        }
        endNode={
          <>
            <Tab
              classes={{ root: classes.smallTab, selected: classes.selectedTab }}
              label={<AddIcon color="primary"/>}
              onClick={() => setShowAddYard(true)}
              disableTouchRipple={true}
            />
          </>
        }
      >
        {/* <Tab
            classes={{ root: classes.smallTab, selected: classes.selectedTab }}
            style={{ marginLeft: theme.spacing(1) }}
            label="All"
            draggable={false}
            disableTouchRipple={true}
            onClick={() => {
              setShowing("all");
            }}
          /> */}
        {binYards.map((n, index) => (
          <Tooltip
            title={
              n.description ? (
                <React.Fragment>
                  <div style={{ fontWeight: "bold" }}>{n.name}</div>
                  <div style={{ marginTop: theme.spacing(0.25) }}>{n.description}</div>
                </React.Fragment>
              ) : (
                n.name
              )
            }
            key={n.name}
          >
            <Tab
              classes={{ root: classes.tab, selected: classes.selectedTab }}
              key={index}
              sx={{ 
                textAlign: "left",
              }}
              disableTouchRipple={true}
              onClick={() => {
                setShowing("bins");
              }}
              label={
                <Grid2 container spacing={3.5} >
                  <Grid2>
                    {n.name}
                  </Grid2>
                  <Grid2 alignItems={"center"}>
                    <MoreVert
                      onMouseEnter={() => setTabClick(false)}
                      onMouseLeave={() => setTabClick(true)}
                      className={classes.icon}
                      onClick={event => {
                        let target = event.currentTarget;
                        setMenuAnchorEl(target);
                        setYardIndex(index);
                      }}
                    />
                  </Grid2>
                </Grid2>
              }
            />
          </Tooltip>
        ))}
        {/* {grainBags.length > 0 && (
          <Tab
            classes={{ root: classes.smallTab, selected: classes.selectedTab }}
            style={{ marginLeft: theme.spacing(1) }}
            label="Bags"
            disableTouchRipple={true}
            onClick={() => {
              setShowing("bags");
            }}
          />
        )} */}
      </DraggableTabs>
    </AppBar>
  );
}