import {
  Button,
  Checkbox,
  CircularProgress,
  DialogActions,
  DialogContent,
  DialogTitle,
  Divider,
  FormControl,
  FormControlLabel,
  FormGroup,
  FormLabel,
  IconButton,
  Link,
  List,
  ListItem,
  ListItemSecondaryAction,
  ListItemText,
  Tab,
  Tabs,
  Theme,
  Tooltip,
  Typography
} from "@mui/material";
import {
  Add as AddIcon,
  Link as LinkIcon,
  LinkOff,
  RemoveCircle as RemoveCircleIcon
} from "@mui/icons-material";
import ResponsiveDialog from "common/ResponsiveDialog";
import { usePermissionAPI, usePrevious, useSnackbar } from "hooks";
import { cloneDeep } from "lodash";
import { binScope, Scope, ShareableLink } from "models";
import moment, { Moment } from "moment";
import { pond } from "protobuf-ts/pond";
import React, { useCallback, useEffect, useState } from "react";
import { openSnackbar } from "providers/Snackbar";
// import { Status } from "@sentry/react";
import { useGateAPI, useBinAPI } from "providers";
import TeamSearch from "./TeamSearch";
import { green, red } from "@mui/material/colors";
import { makeStyles } from "@mui/styles";
import { MobileDateTimePicker } from "@mui/x-date-pickers";

const useStyles = makeStyles((theme: Theme) => {
  return ({
    dialogContent: {
      marginTop: theme.spacing(2)
    },
    formContainer: {
      display: "flex",
      flexWrap: "wrap"
    },
    formControl: {
      margin: theme.spacing(1),
      minWidth: 160,
      width: "100%"
    },
    emailForm: {
      paddingBottom: theme.spacing(2)
    },
    fabContainer: {
      position: "relative",
      minHeight: "64px"
    },
    addIcon: {
      color: green[500],
      "&:hover": {
        color: green[600]
      }
    },
    removeIcon: {
      color: red[500],
      "&:hover": {
        color: red[600]
      }
    },
    grey: {
      color: theme.palette.text.secondary
    }
  });
});

interface Props {
  scope: Scope;
  label: string;
  permissions: pond.Permission[];
  isDialogOpen: boolean;
  closeDialogCallback: Function;
}

export default function ShareObject(props: Props) {
  const binAPI = useBinAPI();
  const gateAPI = useGateAPI();
  const classes = useStyles();
  const permissionAPI = usePermissionAPI();
  const { info, success } = useSnackbar();
  const { scope, label, permissions, isDialogOpen, closeDialogCallback } = props;
  const [sharedPermissions, setSharedPermissions] = useState<pond.Permission[]>([
    pond.Permission.PERMISSION_READ
  ]);
  const [tab, setTab] = useState<number>(0);
  const prevTab = usePrevious(tab);
  const [isLoadingLinks, setIsLoadingLinks] = useState<boolean>(false);
  const [shareableLinks, setShareableLinks] = useState<ShareableLink[]>([]);
  const [newLinkExpiration, setNewLinkExpiration] = useState<Moment>(moment().add(1, "week"));
  const [isNewLinkInfinite, setIsNewLinkInfinite] = useState<boolean>(false);
  const [teamKey, setTeamKey] = useState<string>("");

  const share = () => {
    permissionAPI.shareObjectByKey(scope, teamKey, sharedPermissions).then(resp => {
      let shareBins = true;
      if (resp && resp.data && resp.data.existing) {
        success(label + " was shared with team");
      } else {
        success("Team was sent an email to sign up");
        shareBins = false;
      }
      let successBins = true;
      if (scope.kind === "binyard" && shareBins) {
        binAPI.listBins(1000, 0, "asc", "name", scope.key).then(resp => {
          resp.data.bins.forEach(bin => {
            if (bin.settings) {
              let newScope = binScope(bin.settings?.key);
              permissionAPI.shareObjectByKey(newScope, teamKey, sharedPermissions).catch(_err => {
                successBins = false;
              });
            }
          });
        });
        if (!successBins) {
          openSnackbar("error", "One or more bins failed to share");
        } else {
          openSnackbar("success", "Bins shared");
        }
      }
      let successGates = true;
      if (scope.kind === "terminal" && shareBins) {
        gateAPI
          .listGates(1000, 0, undefined, undefined, undefined, undefined, [scope.key], [scope.kind])
          .then(resp => {
            resp.data.gates.forEach(gate => {
              if (gate) {
                let newScope = { key: gate.key, kind: "gate" } as Scope;
                permissionAPI.shareObjectByKey(newScope, teamKey, sharedPermissions).catch(_err => {
                  successGates = false;
                });
              }
            });
          });
        if (!successGates) {
          openSnackbar("error", "One or more Gates failed to share");
        } else {
          openSnackbar("success", "Gates shared");
        }
      }
      close(true);
    });

    /*permissionAPI
      .shareObject(scope, email, sharedPermissions)
      .then((result: any) => {
        let shareBins = true;
        if (result && result.data && result.data.existing) {
          success(label + " was shared with " + email);
        } else {
          success(email + " was sent an email to sign up");
          shareBins = false;
        }
        let successBins = true;
        if (scope.kind === "binyard" && shareBins) {
          binAPI.listBins(1000, 0, "asc", "name", scope.key).then(resp => {
            resp.data.bins.forEach(bin => {
              if (bin.settings) {
                let newScope = binScope(bin.settings?.key);
                permissionAPI.shareObject(newScope, email, sharedPermissions).catch(err => {
                  successBins = false;
                });
              }
            });
          });
          if (!successBins) {
            openSnackbar("error", "One or more bins failed to share with " + email);
          } else {
            openSnackbar(Status.Success, "Bins shared with " + email);
          }
        }
        closeAfterShare();
      })
      .catch((err: any) => {
        error("Unable to share " + label + " with " + email);
        close();
      });*/
  };

  const loadShareableLinks = useCallback(() => {
    setIsLoadingLinks(true);
    permissionAPI
      .listShareableLinks(scope)
      .then((response: any) => {
        let rawShareableLinks = response.data.links ? response.data.links : [];
        let rShareableLinks = rawShareableLinks.map((rawShareableLink: any) =>
          ShareableLink.any(rawShareableLink)
        );
        setShareableLinks(rShareableLinks);
      })
      .catch((_error: any) => {
        setShareableLinks([]);
        console.log("Error occured while loading shareable links");
      })
      .finally(() => {
        setIsLoadingLinks(false);
      });
  }, [permissionAPI, scope]);

  useEffect(() => {
    if (tab === 1 && prevTab !== tab) {
      loadShareableLinks();
    }
  }, [loadShareableLinks, prevTab, tab]);

  const getNeverExpires = () => {
    return "";
  };

  const createShareableLink = () => {
    const expiration = isNewLinkInfinite ? getNeverExpires() : newLinkExpiration.toISOString();
    permissionAPI
      .addShareableLink(scope, expiration)
      .then((_response: any) => {
        loadShareableLinks();
      })
      .catch((_error: any) => {
        console.log("Error occured while creating shareable link");
      });
  };

  const revokeShareableLink = (code: string) => {
    permissionAPI
      .removeShareableLink(scope, code)
      .then((_response: any) => {
        loadShareableLinks();
      })
      .catch((_error: any) => {
        console.log("Error occured while removing the shareable link");
      });
  };

  const getShareableLinkURL = (code: string): string => {
    const base = window.location.origin;
    return base + "/" + scope.kind + "s/" + code;
  };

  const copyShareableLinkToClipboard = (code: string) => {
    const url = getShareableLinkURL(code);
    navigator.clipboard.writeText(url);
    info("Copied link to clipboard");
  };

  const close = (callback: boolean) => {
    closeDialogCallback(callback);
  };

  const changePermissions = (event: any) => {
    let updatedSharedPermissions: Array<pond.Permission> = cloneDeep(sharedPermissions);
    let permission: pond.Permission;
    switch (event.target.value) {
      case "1":
        permission = pond.Permission.PERMISSION_USERS;
        break;
      case "2":
        permission = pond.Permission.PERMISSION_READ;
        break;
      case "3":
        permission = pond.Permission.PERMISSION_WRITE;
        break;
      case "4":
        permission = pond.Permission.PERMISSION_SHARE;
        break;
      case "6":
        permission = pond.Permission.PERMISSION_FILE_MANAGEMENT;
        break;
      default:
        permission = pond.Permission.PERMISSION_INVALID;
        break;
    }

    if (updatedSharedPermissions.includes(permission)) {
      updatedSharedPermissions = updatedSharedPermissions.filter(
        (curPermission: pond.Permission) => curPermission !== permission
      );
    } else {
      updatedSharedPermissions.push(permission);
    }

    setSharedPermissions(updatedSharedPermissions);
  };

  const changeTab = (_event: any, newTab: number) => {
    setTab(newTab);
  };

  const isValid = () => {
    return teamKey !== "" && sharedPermissions.length > 0;
  };

  // UI BEGINS

  const teamsList = () => {
    return <TeamSearch label="Team" setTeamCallback={setTeamKey} />;
  };

  const permissionsForm = () => {
    return (
      <FormControl component="fieldset" fullWidth variant="outlined">
        <FormLabel component="legend">Permissions</FormLabel>
        <FormGroup>
          {permissions.includes(pond.Permission.PERMISSION_READ) && (
            <FormControlLabel
              control={
                <Checkbox
                  disabled={sharedPermissions.includes(pond.Permission.PERMISSION_READ)}
                  checked={sharedPermissions.includes(pond.Permission.PERMISSION_READ)}
                  onChange={changePermissions}
                  value={pond.Permission.PERMISSION_READ as pond.Permission}
                />
              }
              label="View"
              labelPlacement="end"
            />
          )}

          {permissions.includes(pond.Permission.PERMISSION_WRITE) && (
            <FormControlLabel
              control={
                <Checkbox
                  checked={sharedPermissions.includes(pond.Permission.PERMISSION_WRITE)}
                  onChange={changePermissions}
                  value={pond.Permission.PERMISSION_WRITE as pond.Permission}
                />
              }
              label="Edit"
              labelPlacement="end"
            />
          )}

          {permissions.includes(pond.Permission.PERMISSION_SHARE) && (
            <FormControlLabel
              control={
                <Checkbox
                  checked={sharedPermissions.includes(pond.Permission.PERMISSION_SHARE)}
                  onChange={changePermissions}
                  value={pond.Permission.PERMISSION_SHARE as pond.Permission}
                />
              }
              label="Share"
              labelPlacement="end"
            />
          )}

          {permissions.includes(pond.Permission.PERMISSION_USERS) && (
            <FormControlLabel
              control={
                <Checkbox
                  checked={sharedPermissions.includes(pond.Permission.PERMISSION_USERS)}
                  onChange={changePermissions}
                  value={pond.Permission.PERMISSION_USERS as pond.Permission}
                />
              }
              label="Manage Users"
              labelPlacement="end"
            />
          )}

          {permissions.includes(pond.Permission.PERMISSION_FILE_MANAGEMENT) && (
            <FormControlLabel
              control={
                <Checkbox
                  checked={sharedPermissions.includes(pond.Permission.PERMISSION_FILE_MANAGEMENT)}
                  onChange={changePermissions}
                  value={pond.Permission.PERMISSION_FILE_MANAGEMENT as pond.Permission}
                />
              }
              label="Files"
              labelPlacement="end"
            />
          )}
        </FormGroup>
      </FormControl>
    );
  };

  const emailSharing = () => {
    return (
      <React.Fragment>
        {teamsList()}
        <div style={{ width: "auto", height: "1rem" }} />
        {permissionsForm()}
      </React.Fragment>
    );
  };

  const shareableLinksList = () => {
    const now = moment();
    let items: any[] = [];
    shareableLinks.forEach((link: ShareableLink) => {
      const expiration = moment(link.settings.expiration);
      const neverExpires = link.settings.expiration === getNeverExpires();
      const expired = !neverExpires && expiration < now;
      items.push(
        <ListItem key={link.key()}>
          {expired ? (
            <IconButton disabled>
              <LinkOff />
            </IconButton>
          ) : (
            <Tooltip title="Click to copy link">
              <IconButton onClick={() => copyShareableLinkToClipboard(link.key())}>
                <LinkIcon />
              </IconButton>
            </Tooltip>
          )}

          <ListItemText
            primary={
              expired ? (
                <span className={classes.grey}>{"/devices/" + link.key()}</span>
              ) : (
                <Link href={getShareableLinkURL(link.key())} target="_blank">
                  {"/devices/" + link.key()}
                </Link>
              )
            }
            secondary={
              neverExpires ? (
                "Never expires"
              ) : (
                <Tooltip title={expiration.calendar()}>
                  <span>{(expired ? "Expired " : "Expires ") + expiration.fromNow()}</span>
                </Tooltip>
              )
            }
          />
          <ListItemSecondaryAction>
            <Tooltip title="Revoke shareable link">
              <IconButton onClick={() => revokeShareableLink(link.key())}>
                <RemoveCircleIcon className={classes.removeIcon} />
              </IconButton>
            </Tooltip>
          </ListItemSecondaryAction>
        </ListItem>
      );
    });
    return (
      <List>
        {isLoadingLinks ? <CircularProgress /> : <React.Fragment>{items}</React.Fragment>}
        {shareableLinks.length > 0 && <Divider variant="middle" />}
        <ListItem>
          <FormGroup row>
            <MobileDateTimePicker
              disabled={isNewLinkInfinite}
              // renderInput={props => <TextField {...props} helperText="" />}
              label="Expiration Date"
              value={newLinkExpiration}
              onChange={date => setNewLinkExpiration(date as Moment)}
              disablePast
            />
            <FormControlLabel
              control={
                <Checkbox
                  checked={isNewLinkInfinite}
                  onChange={(_, checked) => setIsNewLinkInfinite(checked)}
                  value="isNewLinkInfinite"
                  color="secondary"
                />
              }
              label="Never expires"
            />
          </FormGroup>
          <ListItemSecondaryAction>
            <Tooltip title="Create new shareable link">
              <IconButton
                className={classes.addIcon}
                color="default"
                onClick={() => createShareableLink()}>
                <AddIcon className={classes.addIcon} />
              </IconButton>
            </Tooltip>
          </ListItemSecondaryAction>
        </ListItem>
      </List>
    );
  };

  const content = () => {
    switch (tab) {
      case 1:
        return <React.Fragment>{shareableLinksList()}</React.Fragment>;
      default:
        return <React.Fragment>{emailSharing()}</React.Fragment>;
    }
  };

  return (
    <ResponsiveDialog
      maxWidth="sm"
      fullWidth
      open={isDialogOpen}
      onClose={() => close(false)}
      aria-labelledby="share-dialog-title">
      <DialogTitle id="share-dialog-title">
        Share
        <Typography variant="body2" color="textSecondary">
          {label}
        </Typography>
      </DialogTitle>
      {scope.kind === "device" && (
        <Tabs value={tab} onChange={changeTab}>
          <Tab label="Share by Email" />
          <Tab label="Shareable Links" />
        </Tabs>
      )}
      <Divider />
      <DialogContent className={classes.dialogContent}>{content()}</DialogContent>
      <DialogActions>
        <Button onClick={() => close(false)} color="primary">
          Cancel
        </Button>
        {tab === 0 && (
          <Button onClick={share} color="primary" disabled={!isValid()}>
            Share
          </Button>
        )}
      </DialogActions>
    </ResponsiveDialog>
  );
}
