import { Box,Grid2 as Grid, Theme, Tooltip, Typography } from "@mui/material";
import { makeStyles } from "@mui/styles";
import MiniPie from "charts/MiniPie";
import { useMobile } from "hooks";
import { clone } from "lodash";
import { pond } from "protobuf-ts/pond";
import React, { useCallback, useEffect, useState } from "react";
import { Marker } from "react-map-gl/mapbox";

//interface for markers
export interface MarkerData {
  title: string; //displayed in the tooltip
  longitude: number;
  latitude: number;
  colour: string;
  centered?: boolean;
  details?: string[];
  markerIcon?: JSX.Element;
  subtype?: number;
  graphPercent?: number; //if defined show graph behind markericon
  customImage?: JSX.Element; //if defined use image rather than basic marker with icon
  customSize?: number; //if the size is different from the normal or mini markers
  mini?: boolean; //whether the marker is the small scouting marker or the normal size object marker
  visibleLevels?: { min?: number; max?: number }; //zoom levels that determine when the marker is visible
  clickFunc?: (event: React.PointerEvent<HTMLElement>, index: number, isMobile: boolean) => void; //function the marker will run when clicked
  updateFunc?: (location: pond.Location) => void; //function the marker will run when something changes
}

interface Props {
  markerData: MarkerData[];
  mapZoomLevel: number;
  dragOn?: boolean;
  groupSelect?: boolean;
  showMarkerTitle?: boolean;
  displayDetails?: boolean;
}

const useStyles = makeStyles((theme: Theme) => ({
    pin: {
      borderRadius: "50rem",
      display: "inline-block",
      borderBottomRightRadius: "0",
      transform: "rotate(45deg)",
      cursor: "pointer",
      boxShadow: "4px 4px 10px black"
    },
    details: {
      transform: "rotate(45deg)",
      background: theme.palette.background.default,
      opacity: 0.75,
      padding: 5,
      borderRadius: 10,
      paddingLeft: 40,
      clipPath: "polygon(25% 0, 100% 0%, 100% 100%, 25% 100%, 0% 50%)"
    },
    titleDisplay: {
      textAlign: "center",
      width: 100,
      marginLeft: -25,
      marginTop: 10,
      backgroundColor: theme.palette.background.default,
      borderRadius: 30,
      boxShadow: "4px 4px 10px black"
    }
}));

export default function Markers(props: Props) {
  const { markerData, dragOn, mapZoomLevel, displayDetails, showMarkerTitle, groupSelect } = props;
  const classes = useStyles();
  const isMobile = useMobile();
  const [groupedMarkers, setGroupedMarkers] = useState<Map<number, MarkerData>>(new Map());

  const moveGroup = (oldLong: number, oldLat: number, newLong: number, newLat: number) => {
    //find the diff of the oldLong (the starting longitude of the marker that was actually dragged) and the newLong
    const diffLong = newLong - oldLong;
    //find the diff of the oldLat and new Lat
    const diffLat = newLat - oldLat;

    let gm = clone(groupedMarkers);

    gm.forEach(marker => {
      if (marker.updateFunc) {
        marker.longitude = marker.longitude + diffLong;
        marker.latitude = marker.latitude + diffLat;
        marker.updateFunc(
          pond.Location.create({ longitude: marker.longitude, latitude: marker.latitude })
        );
      }
    });
    setGroupedMarkers(gm);
  };

  //when group select is turned off, clear the grouped markers
  useEffect(() => {
    if (!groupSelect) {
      setGroupedMarkers(new Map());
    }
  }, [groupSelect]);

  const renderMarkers = useCallback(() => {
    let markerList: JSX.Element[] = [];
    markerData.forEach((marker, index) => {
      let markerSize = marker.mini ? 20 : 50;
      if (marker.customSize) {
        markerSize = marker.customSize;
      }

      let yOff = 0;
      if (!marker.centered) {
        yOff = -markerSize * 0.7;
      }

      let vis = "block";
      if (marker.visibleLevels) {
        let max = marker.visibleLevels.max;
        let min = marker.visibleLevels.min;
        if ((max && mapZoomLevel > max) || (min && mapZoomLevel < min)) {
          vis = "none";
        }
      }

      let gm = groupedMarkers.get(index);
      if (gm) {
        marker.longitude = gm.longitude;
        marker.latitude = gm.latitude;
      }

      let border = marker.customImage ? "" : "1px solid white";
      if (gm) {
        border = "2px solid black";
      }

      let blah: JSX.Element = (
        <Marker
          //style={{border: gm ? "2px solid black" : ""}}
          key={"marker-" + index}
          longitude={marker.longitude}
          latitude={marker.latitude}
          //offsetTop={yOff}
          offset={[0, yOff]}
          draggable={dragOn}
          onDragEnd={e => {
            let newLong = e.lngLat.lng;
            let newLat = e.lngLat.lat;
            if (groupSelect && groupedMarkers.size > 0) {
              moveGroup(marker.longitude, marker.latitude, newLong, newLat);
            } else {
              if (marker.updateFunc) {
                marker.longitude = newLong;
                marker.latitude = newLat;
                marker.updateFunc(
                  pond.Location.create({ latitude: e.lngLat.lat, longitude: e.lngLat.lng })
                );
              }
            }
          }}>
          <Box id={"marker-" + index} />
          <Tooltip title={marker.title} placement={"right"} arrow>
            <Box
              className={!marker.customImage ? classes.pin : undefined}
              style={{
                display: vis,
                border: border,
                background: marker.customImage ? "none" : marker.colour,
                width: markerSize,
                height: markerSize
              }}
              onPointerUp={e => {
                if (!dragOn && marker.clickFunc) {
                  marker.clickFunc(e, index, isMobile);
                } else if (groupSelect) {
                  let group = clone(groupedMarkers);
                  group.set(index, marker);
                  setGroupedMarkers(group);
                }
              }}>
              {marker.graphPercent !== undefined && (
                <Box
                  width={"100%"}
                  height={"100%"}
                  style={{ pointerEvents: "none", position: "absolute" }}>
                  <MiniPie
                    max={100}
                    current={marker.graphPercent}
                    colour={marker.colour}
                    size={markerSize}
                  />
                </Box>
              )}
              {marker.customImage ? (
                marker.customImage
              ) : (
                <Box
                  style={{
                    transform: "rotate(-45deg)",
                    width: markerSize * 0.6,
                    height: markerSize * 0.6,
                    paddingTop: marker.mini ? "10%" : "30%",
                    pointerEvents: "none"
                  }}>
                  {marker.markerIcon}
                </Box>
              )}
              {marker.details && displayDetails && (
                <Box
                  className={classes.details}
                  style={{
                    position: "absolute",
                    left: markerSize / 2,
                    top: markerSize / 2,
                    width: 200,
                    marginTop: 80
                  }}>
                  <Grid container direction="column" wrap="nowrap">
                    {marker.details.map((detail, i) => (
                      <Grid key={i}>
                        <Typography noWrap style={{ fontSize: 10, fontWeight: 750, height: 15 }}>
                          {detail}
                        </Typography>
                      </Grid>
                    ))}
                  </Grid>
                </Box>
              )}
            </Box>
          </Tooltip>
          {showMarkerTitle && <Box className={classes.titleDisplay}>{marker.title}</Box>}
        </Marker>
      );
      markerList.push(<React.Fragment key={index}>{blah}</React.Fragment>);
    });
    return markerList;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [
    markerData,
    classes,
    displayDetails,
    dragOn,
    groupSelect,
    groupedMarkers,
    isMobile,
    showMarkerTitle,
    mapZoomLevel
  ]);

  return <React.Fragment>{renderMarkers()}</React.Fragment>;
}
