import { Gate as IGate } from "models/Gate";
//import { MatchParams } from "navigation/Routes";
//import { Redirect, useHistory, useRouteMatch } from "react-router";
import React, { useCallback, useEffect, useState } from "react";
import PageContainer from "./PageContainer";
import { useGlobalState, useGateAPI, useUserAPI } from "providers";
import {
  Box,
  ButtonBase,
  Card,
  CircularProgress,
  Drawer,
  Grid2 as Grid,
  IconButton,
  MenuItem,
  Tab,
  Tabs,
  Theme,
  Typography
} from "@mui/material";
import { pond } from "protobuf-ts/pond";
import DeviceLinkDrawer from "common/DeviceLinkDrawer";
import { Component, Device, Scope } from "models";
import GateActions from "gate/GateActions";
import GateDevice from "gate/GateDevice";
import ObjectControls from "common/ObjectControls";
import { Link } from "@mui/icons-material";
import Chat from "chat/Chat";
import PlaneIcon from "products/AviationIcons/PlaneIcon";
import NotesIcon from "@mui/icons-material/Notes";
import { useMobile, useSnackbar, useThemeType } from "hooks";
import { clone } from "lodash";
import { useNavigate, useParams } from "react-router-dom";
import { makeStyles } from "@mui/styles";


interface TabPanelProps {
  children?: React.ReactNode;
  index: any;
  value: any;
}

function TabPanelMine(props: TabPanelProps) {
  const { children, value, index, ...other } = props;

  return (
    <div
      role="tabpanel"
      hidden={value !== index}
      aria-labelledby={`simple-tab-${index}`}
      {...other}>
      {value === index && <React.Fragment>{children}</React.Fragment>}
    </div>
  );
}

interface Props {
  gateKey?: string;
  useMobile?: boolean;
}

const useStyles = makeStyles((theme: Theme) => ({
  //const themeType = theme.palette.type;
    inactiveButton: {
      color: useThemeType() === "light" ? theme.palette.common.black : theme.palette.common.white,
      backgroundColor: "transparent",
      width: theme.spacing(5),
      height: theme.spacing(5),
      border: "1px solid",
      borderColor: theme.palette.divider
    },
    activeButton: {
      color: useThemeType() === "light" ? theme.palette.common.black : theme.palette.common.white,
      backgroundColor: theme.palette.primary.main,
      width: theme.spacing(5),
      height: theme.spacing(5),
      border: "1px solid",
      borderColor: theme.palette.divider
    },
    drawerPaper: {
      height: "100%",
      width: "30%"
    }
}));

export default function Gate(props: Props) {
  //const match = useRouteMatch<MatchParams>();
  //const gateID = props.gateID ?? match.params.gateID;
  const { gateKey } = props
  const gateID = gateKey ?? useParams<{ gateKey: string }>()?.gateKey ?? "";
  const classes = useStyles();
  const gateAPI = useGateAPI();
  const userAPI = useUserAPI();
  const [gate, setGate] = useState<IGate>(IGate.create());
  const [devices, setDevices] = useState<Map<string, pond.ComprehensiveDevice>>(
    new Map<string, pond.ComprehensiveDevice>()
  );
  const [components, setComponents] = useState<Component[]>([]);
  const [openDeviceDrawer, setOpenDeviceDrawer] = useState(false);
  const [loadingGate, setLoadingGate] = useState(false);
  const [{ user, as }] = useGlobalState();
  const [permissions, setPermissions] = useState<pond.Permission[]>([]);
  const [tabVal, setTabVal] = useState(0);
  //const history = useHistory();
  const navigate = useNavigate();
  const [displayTab, setDisplayTab] = useState(0);
  const [openNoteDrawer, setOpenNoteDrawer] = useState(false);
  const isMobile = useMobile();
  const [devPrefs, setDevPrefs] = useState<Map<number, number>>(new Map<number, number>());
  const { openSnack } = useSnackbar();
  const [invalid, setInvalid] = useState(false);

  const goToMap = () => {
    navigate("/aviationMap", { state: { long: gate.longitude(), lat:gate.latitude() }})
  };

  useEffect(() => {
    let key = gateID;
    let kind = "gate";
    if (as) {
      key = as;
      kind = "team";
    }
    userAPI.getUser(user.id(), { key: key, kind: kind } as Scope).then(resp => {
      setPermissions(resp.permissions);
    });
  }, [as, gateID, userAPI, user]);

  const loadGate = useCallback(() => {
    let id = gateID;
    setTabVal(0);
    if (loadingGate || id === undefined || id === "") return;
    setLoadingGate(true);
    gateAPI
      .getGatePageData(id, as)
      .then(resp => {
        //console.log(resp.data);
        let p = new Map<number, pond.GateDeviceType>();
        Object.keys(resp.data.preferences).forEach(k => {
          let prefKey = parseInt(k);
          p.set(
            prefKey,
            pond.GatePreferences.fromObject(resp.data.preferences[k]).gateDevice ??
              pond.GateDeviceType.GATE_DEVICE_TYPE_UNKNOWN
          );
        });
        setDevPrefs(p);
        if (resp.data.gate) {
          setGate(IGate.any(resp.data.gate));
        }
        if (resp.data.linkedDevices) {
          let devMap = new Map<string, pond.ComprehensiveDevice>();
          resp.data.linkedDevices.forEach(dev => {
            if (dev.device?.settings?.deviceId) {
              devMap.set(dev.device.settings.deviceId.toString(), dev);
            }
          });
          setDevices(devMap);
        }
        if (resp.data.linkedComponents) {
          setComponents(resp.data.linkedComponents.map(c => Component.any(c)));
        }
      })
      .catch(err => {
        setInvalid(true);
      })
      .finally(() => {
        setLoadingGate(false);
      });
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [gateAPI, gateID, as]);

  useEffect(() => {
    loadGate();
  }, [loadGate]);

  const updateGateDevicePrefs = (deviceID: number, newPref: pond.GateDeviceType) => {
    gateAPI
      .updatePrefs(gate.key, "device", deviceID.toString(), newPref, [gate.key], ["gate"], as)
      .then(resp => {
        openSnack("Updated gate device type");
        // have to do the clone method to force the select box to update
        let newPrefMap = clone(devPrefs);
        newPrefMap.set(deviceID, newPref);
        setDevPrefs(newPrefMap);
      })
      .catch(err => {
        openSnack("Failed to update device type");
      });
  };

  const deviceDrawer = () => {
    return (
      <DeviceLinkDrawer
        //the mipca tag was not working for some reason so just taking the tags out
        //and this way we dont have to worry about tagging them when they are provisioned
        //deviceTags={["omniair", "mipca", "MiPCA", "Mipca"]} 
        devicePrefMap={devPrefs}
        prefOptions={[
          <MenuItem
            key={pond.GateDeviceType.GATE_DEVICE_TYPE_UNKNOWN}
            value={pond.GateDeviceType.GATE_DEVICE_TYPE_UNKNOWN}>
            None
          </MenuItem>,
          <MenuItem
            key={pond.GateDeviceType.GATE_DEVICE_TYPE_PCA}
            value={pond.GateDeviceType.GATE_DEVICE_TYPE_PCA}>
            PCA Unit
          </MenuItem>
        ]}
        devicePrefChanged={(device, pref) => {
          updateGateDevicePrefs(device.id(), pref);
        }}
        open={openDeviceDrawer}
        close={() => {
          setOpenDeviceDrawer(false);
        }}
        linkedDevices={devices}
        linkedComponents={components}
        updateLinkedDevices={(device, linked) => {
          let devMap = devices;
          let id = device.device?.settings?.deviceId;
          if (id) {
            if (linked) {
              gateAPI
                .updateLink(gateID, "gate", id.toString(), "device", [
                  "read",
                  "write",
                  "grant",
                  "revoke"
                ], as)
                .then(resp => {
                  if (id) {
                    devMap.set(id.toString(), device);
                    setTabVal(id);
                  }
                  setDevices(devMap);
                })
                .catch(err => {
                  console.log("error linking device");
                });
            } else {
              gateAPI.updateLink(gateID, "gate", id.toString(), "device", [], as).then(resp => {
                if (id) {
                  devMap.delete(id.toString());
                  if (tabVal === id) {
                    let firstEntry = Array.from(devMap.values())[0];
                    if (firstEntry) {
                      setTabVal(firstEntry.device?.settings?.deviceId ?? -1);
                    } else {
                      setTabVal(0);
                    }
                  }
                }
                setDevices(devMap);
              });
            }
          }
        }}
        updateLinkedComponents={(deviceID, component, linked) => {
          let c = components;
          if (linked) {
            gateAPI
              .updateLink(gateID, "gate", deviceID + ":" + component.key(), "component", [
                "read",
                "write",
                "grant",
                "revoke"
              ],as)
              .then(resp => {
                c.push(component);
                setComponents([...c]);
              });
          } else {
            gateAPI
              .updateLink(gateID, "gate", deviceID + ":" + component.key(), "component", [], as)
              .then(resp => {
                c.forEach((comp, i) => {
                  if (component.key() === comp.key()) {
                    c.splice(i, 1);
                    setComponents([...c]);
                  }
                });
              });
          }
        }}
      />
    );
  };

  const gateDisplay = () => {
    return (
      <React.Fragment>
        {loadingGate ? (
          <Card>
            <Box display="flex" justifyContent="center" alignItems="center" style={{ height: 300 }}>
              <CircularProgress size={200} thickness={1.5} />
            </Box>
          </Card>
        ) : (
          <React.Fragment>
            <Card
              style={{
                //padding: isMobile ? 2 : 15,
                marginLeft: isMobile ? 0 : 15,
                marginRight: isMobile ? 0 : 15
              }}>
              <Tabs
                style={{
                  marginBottom: 5,
                  display: Array.from(devices.keys()).length < 2 ? "none" : "block"
                }}
                value={tabVal}
                indicatorColor="secondary"
                //textColor="secondary"
                onChange={(_, newVal) => {
                  setTabVal(newVal);
                }}
                aria-label="device tabs">
                <Tab label={"Device Not Found"} value={-1} style={{ display: "none" }} />
                <Tab label={"No Connected Devices"} value={0} style={{ display: "none" }} />
                {Array.from(devices.values()).map(dev => {
                  let name = "Device Not Found";
                  let devKey = -1;
                  if (dev.device && dev.device.settings) {
                    name = dev.device.settings.name;
                    devKey = dev.device.settings.deviceId;
                  }
                  return <Tab key={devKey} label={name ?? devKey} value={devKey} />;
                })}
              </Tabs>
              {/* panel to show if there are no devices */}
              <TabPanelMine value={tabVal} index={0}>
                <ButtonBase
                  onClick={() => {
                    setOpenDeviceDrawer(true);
                  }}
                  style={{ height: 150, width: "100%", margin: -15 }}>
                  <Grid
                    width="100%"
                    container
                    direction="row"
                    spacing={2}
                    alignItems="center"
                    alignContent="center">
                    <Grid size={12}>
                      <Box display="flex" justifyContent="center" alignItems="center">
                        <Link style={{ height: 50, width: 50 }} />
                        <Typography paddingLeft={2} style={{ fontSize: 25, fontWeight: 650 }}>
                          Connect Device
                        </Typography>
                      </Box>
                    </Grid>
                    <Grid size={12}>
                      Click here to add a device to the gate. To add an additional device to a gate
                      use the "Link Device" icon on the top right side of this page
                    </Grid>
                  </Grid>
                </ButtonBase>
              </TabPanelMine>
              {/* panel to show if there was an issue in the tab */}
              <TabPanelMine value={tabVal} index={-1}>
                Device Not Found
              </TabPanelMine>
              {Array.from(devices.values()).map(dev => {
                let devKey = 0;
                if (dev.device && dev.device.settings) {
                  devKey = dev.device.settings.deviceId;
                  if (tabVal === 0) {
                    setTabVal(devKey);
                  }
                }
                return (
                  <TabPanelMine key={devKey} value={tabVal} index={devKey}>
                    <GateDevice
                      key={devKey}
                      comprehensiveDevice={dev}
                      gate={gate}
                      linkedCompList={components}
                      drawerView={props.useMobile}
                    />
                  </TabPanelMine>
                );
              })}
            </Card>
          </React.Fragment>
        )}
      </React.Fragment>
    );
  };

  const noteDrawer = () => {
    return (
      <Drawer
        open={openNoteDrawer}
        onClose={() => {
          setOpenNoteDrawer(false);
        }}
        anchor="right"
        classes={{ paper: classes.drawerPaper }}>
        <Box padding={2}>
          <Typography>Notes</Typography>
          <Card style={{ padding: 10 }}>
            <Chat objectKey={gate.key} type={pond.NoteType.NOTE_TYPE_GATE} />
          </Card>
        </Box>
      </Drawer>
    );
  };

  return (
    <PageContainer>
      <ObjectControls
        objectButton={
          <IconButton
            size="small"
            style={{
              marginTop: "0.3625rem",
              marginBottom: "0.3625rem",
              marginRight: "0.5rem"
            }}
            onClick={() => {
              setDisplayTab(0);
            }}
            className={displayTab === 0 ? classes.activeButton : classes.inactiveButton}
            component="span">
            <PlaneIcon />
          </IconButton>
        }
        linkDeviceFunction={() => {
          setOpenDeviceDrawer(true);
        }}
        notesButton={
          <IconButton
            onClick={() => {
              if (props.useMobile || isMobile) {
                setDisplayTab(1);
              } else {
                setOpenNoteDrawer(true);
              }
            }}
            size="small"
            style={{
              marginTop: "0.3625rem",
              marginBottom: "0.3625rem",
              marginRight: "0.5rem"
            }}
            className={displayTab === 1 ? classes.activeButton : classes.inactiveButton}
            component="span">
            <NotesIcon />
          </IconButton>
        }
        mapFunction={() => {
          goToMap();
        }}
        actions={<GateActions gate={gate} refreshCallback={loadGate} permissions={permissions} />}
        permissions={permissions}
        devices={Array.from(devices.values()).map(compDev => Device.any(compDev.device))}
      />
      <Box marginLeft={2} marginTop={isMobile ? -1.5 : -1} marginBottom={isMobile ? 0 : 1}>
        <Typography style={{ fontSize: 25, fontWeight: 650 }}>{gate.name}</Typography>
      </Box>
      <TabPanelMine value={displayTab} index={0}>
        {gateDisplay()}
      </TabPanelMine>
      {/* tab for notes on mobile and the map drawer */}
      <TabPanelMine value={displayTab} index={1}>
        <Card style={{ padding: 10 }}>
          <Chat objectKey={gate.key} type={pond.NoteType.NOTE_TYPE_GATE} />
        </Card>
      </TabPanelMine>
      {/* drawer is for displaying notes on desktop */}
      {noteDrawer()}
      {deviceDrawer()}
    </PageContainer>
  );
}
