import { Button } from "@material-ui/core";
import L from "leaflet";
import React, { useEffect, useState } from "react";
import { MapContainer, Marker, Popup, TileLayer, useMap } from "react-leaflet";
import useStyles from "../useStyles";

import GrayMarkerIcon from "../../assets/gray-marker.png";
import GreenMarkerIcon from "../../assets/green-marker.png";
import { DropDownList } from "../Controls/DropDownList";
import { logger } from "../../services/monitoring";
import { ValidateLocationData } from "../../utils/locations";
import { useUserContext } from "../Contexts/UserContext";
import { useVehicleContext, VehicleProvider } from "../Contexts/VehicleContext";
import { VehiclePopUp } from "./popup";
import { useLocalStorage } from "../useLocalStorage";
import zoomLocations from './zoomLocations.json';

const Component = () => {
  const classes = useStyles();
  const {
    token: {
      idToken: { jwtToken: token },
    },
  } = useUserContext();
  const { getConnections, getLocations, getState } = useVehicleContext();

  const REQUEST_INTERVAL = 10000;

  const [center, setCenter] = useState([0, 0]);
  const [zoom, setZoom] = useState(2);
  const [markers, setMarkers] = useState([]);
  const [connections, setConnections] = useState({});
  const [lastMapCenter, setLastMapCenter] = useLocalStorage("MAP_CENTER", "");

  useEffect(() => {
    if (!token) return;
    retrieveAndStoreLocations(token).then((points) => {
      centerAroundMarkers(points);
    });
    const id = setInterval(function () {
      retrieveAndStoreLocations(token);
    }, REQUEST_INTERVAL);
    return () => {
      clearInterval(id);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [token]);

  const retrieveAndStoreLocations = (accessToken) => {
    return getLocations(accessToken)
      .then((result) => {
        if (result.data != null && ValidateLocationData(result.data) !== false) {
          const points = result.data.map((point) => [
            point.latitude,
            point.longitude,
            point.vin,
          ]);
          setMarkers(points);
          return points;
        }
        return [];
      })
      .catch((error) => logger.warn(error.stack));
  };

  const centerAroundMarkers = (points) => {
    if (lastMapCenter) {
      let zoomLocation = JSON.parse(lastMapCenter)
      setCenter(zoomLocation.center);
      setZoom(zoomLocation.zoom)
    } else {
      let defaultLocationJSON = process.env.REACT_APP_HOME_MAP_DEFAULT_LOCATION;
      let defaultLocation = JSON.parse(defaultLocationJSON)
      setCenter([defaultLocation.lat, defaultLocation.lng]);
      setZoom(defaultLocation.zoom);
    }
  };

  useEffect(() => {
    if (!token) return;

    const vins = markers
      .filter((marker) => marker[2].length > 0)
      .map((marker) => marker[2]);

    if (vins.length === 0) return;

    getConnections(vins, token).then((conns) => {
      setConnections(conns);
    });
    // eslint-disable-next-line
  }, [markers, token]);

  const [selectedVIN, setSelectedVIN] = useState(null);
  const [carState, setCarState] = useState(null);

  useEffect(() => {
    if (selectedVIN != null) {
      retrieveAndStoreCarState(selectedVIN);
      const id = setInterval(function () {
        retrieveAndStoreCarState(selectedVIN);
      }, REQUEST_INTERVAL);
      return () => {
        clearInterval(id);
      };
    }
    // eslint-disable-next-line
  }, [selectedVIN]);

  const selectCar = (e, vin) => {
    e.preventDefault();
    setSelectedVIN(vin);
  };

  const focusMap = (e) => {
    setLastMapCenter(e.target.value)
    let zoomLocation = JSON.parse(e.target.value)
    setCenter(zoomLocation.center);
    setZoom(zoomLocation.zoom)
  }

  const retrieveAndStoreCarState = (vin) => {
    getState(token, vin).then((results) => {
      setCarState({ ...results.data, vin: vin });
    });
  };

  const handleClose = () => {
    setSelectedVIN(null);
    setCarState(null);
  };

  const isOnline = (vin) => {
    return connections[vin];
  };

  const getZIndex = (vin) => {
    if (isOnline(vin)) return 1000;
    return 0;
  };

  function getCarIcon(vin) {
    let icon = GrayMarkerIcon;

    if (isOnline(vin)) {
      icon = GreenMarkerIcon;
    }

    return new L.Icon({
      iconUrl: icon,
      iconAnchor: [24, 42],
    });
  }

  return (
    <>
      <DropDownList label="Zoom To" data={zoomLocations} classes={classes} onChange={focusMap} value={lastMapCenter} />
      <MapContainer
        center={center}
        zoom={zoom}
        style={{
          width: "100%",
          height: "900px",
        }}
      >
        <TileLayer
          attribution='&copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />
        <CenterFocus center={center} zoom={zoom} />
        {markers.map((marker) => (
          <Marker
            icon={getCarIcon(marker[2])}
            key={marker[2]}
            position={[marker[0], marker[1]]}
            title={marker[2]}
            opacity={0.9}
            zIndexOffset={getZIndex(marker[2])}
          >
            <Popup>
              <div align="center">
                <p className={classes.markerTitle}>
                  <b>{marker[2]}</b>
                </p>
                <Button
                  type="submit"
                  variant="contained"
                  color="primary"
                  onClick={(e) => selectCar(e, marker[2])}
                >
                  View Stats
                </Button>
              </div>
            </Popup>
          </Marker>
        ))}

        {carState ? (
          <VehiclePopUp
            key={carState.vin}
            {...carState}
            className={classes.popup}
            onClose={handleClose}
          />
        ) : null}
      </MapContainer>
    </>
  );
};

const CenterFocus = ({ center, zoom }) => {
  const map = useMap();

  useEffect(() => {
    if (center[0] === 0 && center[1] === 0) {
      map.flyTo([0, 0], 2, { duration: 1.5 });
    } else {
      map.flyTo(center, zoom, { duration: 1.5 });
    }
  }, [center, zoom, map]);

  return null;
};

const VehicleMap = () => (
  <VehicleProvider>
    <Component />
  </VehicleProvider>
);

export default VehicleMap;
