import { Box, Typography } from "@mui/material";
import DeviceLinkDrawer from "common/DeviceLinkDrawer";
import DisplayDrawer from "common/DisplayDrawer";
import MapMarkerSettings from "maps/MapMarkerSettings";
import { Device, Site } from "models";
import { ObjectHeater } from "models/ObjectHeater";
import ObjectHeaterCard from "objectHeater/ObjectHeaterCard";
import { pond } from "protobuf-ts/pond";
import { useGlobalState, useObjectHeaterAPI, useSiteAPI, useSnackbar } from "providers";
import React, { useEffect, useState } from "react";

interface Props {
  open: boolean;
  onClose: () => void;
  selectedSite: string;
  sites: Map<string, Site>;
  heaters: Map<string, pond.ObjectHeaterData[]>;
  removeMarker: (key: string) => void;
  updateMarker: (key: string, newSettings: pond.SiteSettings) => void;
  moveMap: (long: number, lat: number) => void;
  reLoadSites: () => void;
}

export default function SiteDrawer(props: Props) {
  const {
    open,
    onClose,
    selectedSite,
    sites,
    removeMarker,
    moveMap,
    heaters,
    reLoadSites,
    updateMarker
  } = props;
  const [site, setSite] = useState<Site>(Site.create());
  const [{as}] = useGlobalState();
  const siteAPI = useSiteAPI();
  const objectHeaterAPI = useObjectHeaterAPI();
  const { openSnack } = useSnackbar();
  const [linkDrawer, setLinkDrawer] = useState(false);
  const [linkedDevices, setLinkedDevices] = useState<Map<string, pond.ComprehensiveDevice>>(
    new Map<string, pond.ComprehensiveDevice>()
  );
  const [selectedHeater, setSelectedHeater] = useState<ObjectHeater>();
  const [openMarkerSettings, setOpenMarkerSettings] = useState(false);

  useEffect(() => {
    let s = sites.get(selectedSite);
    if (s) {
      setSite(s);
    }
  }, [selectedSite, sites]);

  const closeDrawer = () => {
    onClose();
  };

  const displayNext = () => {
    let devArr = Array.from(sites.values());
    let index = devArr.indexOf(site);
    let found = false;
    do {
      if (index === devArr.length - 1) {
        index = 0;
      } else {
        index++;
      }
      let nextSite = devArr[index];
      if (
        nextSite.location().longitude !== 0 &&
        nextSite.location().longitude !== 0 &&
        nextSite.location().latitude !== undefined &&
        nextSite.location().longitude !== undefined
      ) {
        setSite(nextSite);
        moveMap(nextSite.location().longitude, nextSite.location().latitude);
        found = true;
      }
    } while (!found);
  };

  const displayPrev = () => {
    let devArr = Array.from(sites.values());
    let index = devArr.indexOf(site);
    let found = false;
    do {
      if (index === 0) {
        index = devArr.length - 1;
      } else {
        index--;
      }
      let nextSite = devArr[index];
      if (
        nextSite.location().longitude !== 0 &&
        nextSite.location().longitude !== 0 &&
        nextSite.location().latitude !== undefined &&
        nextSite.location().longitude !== undefined
      ) {
        setSite(nextSite);
        moveMap(nextSite.location().longitude, nextSite.location().latitude);
        found = true;
      }
    } while (!found);
  };

  const deviceLinkDrawer = () => {
    return (
      <DeviceLinkDrawer
        open={linkDrawer}
        close={() => {
          setLinkDrawer(false);
        }}
        linkedDevices={linkedDevices}
        updateLinkedDevices={(dev, linked) => {
          let deviceID = dev.device?.settings?.deviceId;
          if (deviceID) {
            if (linked && selectedHeater) {
              objectHeaterAPI
                .updateLink(selectedHeater.key, "objectHeater", deviceID.toString(), "device", [
                  "read",
                  "write",
                  "grant",
                  "revoke"
                ], as)
                .then(resp => {
                  setLinkDrawer(false);
                  reLoadSites();
                });
            }
          }
        }}
      />
    );
  };

  const drawerBody = () => {
    let siteHeaters = heaters.get(site.key());
    return (
      <Box padding={2}>
        {siteHeaters ? (
          siteHeaters.map(h => (
            <ObjectHeaterCard
              key={h.heater?.key}
              heaterData={h}
              linkDevice={(heater, linkedDevices) => {
                setSelectedHeater(heater);
                setLinkDrawer(true);
                let d = new Map<string, pond.ComprehensiveDevice>();
                linkedDevices.forEach(compDev => {
                  let device = Device.any(compDev.device);
                  d.set(device.id().toString(), compDev);
                });
                setLinkedDevices(d);
              }}
            />
          ))
        ) : (
          <Typography>No Heaters Found</Typography>
        )} 
      </Box>
    );
  };

  /**
   * function to remove the marker and coordinates from the object
   */
  const remove = () => {
    siteAPI
      .removeSite(site.key())
      .then(resp => {
        openSnack("Site Deleted");
        //then use the removeMarker prop function to update the markers in the parent map
        removeMarker(site.key());
      })
      .catch(err => {
        openSnack("Failed to remove marker");
      });
  };

  const update = () => {
    setOpenMarkerSettings(true);
  };

  return (
    <React.Fragment>
      {deviceLinkDrawer()}
      <DisplayDrawer
        open={open}
        onClose={closeDrawer}
        displayNext={displayNext}
        displayPrev={displayPrev}
        title={site.siteName()}
        width={"40vw"}
        drawerBody={drawerBody()}
        updateElement={update}
        removeElement={remove}
      />
      <MapMarkerSettings
        close={() => {
          setOpenMarkerSettings(false);
        }}
        open={openMarkerSettings}
        colourControl
        theme={site.settings.theme ?? pond.ObjectTheme.create()}
        updateObject={newTheme => {
          let settings = site.settings;
          settings.theme = newTheme;
          siteAPI
            .updateSite(site.key(), settings, undefined, as)
            .then(resp => {
              openSnack("marker settings updated");
              updateMarker(site.key(), settings);
            })
            .catch(() => {
              openSnack("failed to update marker settings");
            });
        }}
      />
    </React.Fragment>
  );
}
