import ReactDOM from "react-dom";
import Popup from "./coordinate-popup";
import Overlay from "ol/Overlay";
import { transform } from "ol/proj";
import throttle from "lodash/throttle";

export default {
  name: "coordinateDisplay",

  getReducer() {
    const initialData = {
      values: {
        X: "0.0000",
        Y: "0.0000",
      },
      latLonInput: {
        X: "",
        Y: "",
      },
      copyActive: false,
      overlay: null,
      container: null,
      _shouldInitialize: false,
    };

    return (state = initialData, { type, payload }) => {
      switch (type) {
        case "MAP_INITIALIZED":
          return Object.assign({}, state, {
            _shouldInitialize: true,
          });
        case "COORD_COPY_ACTIVE":
        case "COORD_COPIED":
        case "COORD_INPUT_UPDATED":
        case "COORD_INPUT_INVALID":
        case "COORD_INITIALIZE_START":
        case "COORD_INITIALIZE_FINISH":
        case "COORD_POSITION_UPDATE":
        case "COORD_OVERLAY_RENDERED":
        case "COORD_OVERLAY_REMOVED":
          return Object.assign({}, state, payload);
        default:
          return state;
      }
    };
  },
  doCoordsInitialize: () => ({ dispatch, store }) => {
    dispatch({
      type: "COORD_INITIALIZE_START",
      payload: {
        _shouldInitialize: false,
      },
    });

    const map = store.selectMap();
    map.on("pointermove", throttle(store.doCoordsPointerMove, 200));

    dispatch({
      type: "COORD_INITIALIZE_FINISH",
    });
  },
  doCoordsPointerMove: (e) => ({ dispatch, store }) => {
    e.preventDefault();
    e.stopPropagation();

    const displayProjection = store.selectDisplayProjection();
    const coord = e.coordinate;
    const projected = transform(coord, "EPSG:3857", displayProjection);
    const X = Math.round(projected[0] * 10000) / 10000;
    const Y = Math.round(projected[1] * 10000) / 10000;

    dispatch({
      type: "COORD_POSITION_UPDATE",
      payload: {
        values: { X, Y },
      },
    });
  },
  doRenderCoordsOverlay: (center, coords) => ({ dispatch, store }) => {
    const map = store.selectMap();
    const hasCoordsOverlay = store.selectCoordsOverlay();

    if (hasCoordsOverlay) {
      store.doClearCoordOverlay(hasCoordsOverlay);
    }
    //generate overlay
    const el = document.createElement("div");
    const overlay = new Overlay({
      element: el,
      positioning: "bottom-center",
      offset: [0, -10],
    });

    //add overlay to map
    map.addOverlay(overlay);
    ReactDOM.render(
      <Popup
        overlay={overlay}
        coords={coords}
        map={map}
        onClear={store.doClearPopup}
      />,
      el
    );

    overlay.setPosition(center);
    dispatch({ type: "COORD_OVERLAY_RENDERED", payload: { overlay: overlay } });
  },
  doClearPopup: (e, overlay) => ({ store }) => {
    console.log(e);
    e.preventDefault();
    e.stopPropagation();
    store.doClearCoordOverlay(overlay);
  },
  doClearCoordOverlay: (overlay) => ({ dispatch, store }) => {
    const map = store.selectMap();
    overlay.setPosition(undefined);
    const el = overlay.getElement();
    el.parentNode.removeChild(el);
    map.removeOverlay(overlay);
    dispatch({ type: "COORD_OVERLAY_REMOVED", payload: { overlay: null } });
  },
  doStartCoordCopy: () => ({ dispatch, store }) => {
    const map = store.selectMap();
    store.doSetCursor("crosshair");

    //Parent container for coord copy.
    const container = document.createElement("div");
    container.id = "cm-copy-coords";
    document.body.appendChild(container);

    dispatch({
      type: "COORD_COPY_ACTIVE",
      payload: {
        copyActive: true,
        container: container,
        notification: {
          message: "Click on map to copy coordinates.",
          level: "info",
        },
      },
    });

    //listen once for click event
    map.once("singleclick", store.doCoordCopy);
  },
  doCoordCopy: (e) => ({ dispatch, store }) => {
    e.preventDefault();
    e.stopPropagation();

    const copyContainer = store.selectCoordsContainer();
    const displayProjection = store.selectDisplayProjection();
    const coord = e.coordinate;
    const projected = transform(coord, "EPSG:3857", displayProjection);
    const x = Math.round(projected[0] * 10000) / 10000;
    const y = Math.round(projected[1] * 10000) / 10000;

    //Add temp input node to use execCommand.
    const valueEl = document.createElement("input");
    copyContainer.appendChild(valueEl);
    valueEl.value = `${x}, ${y}`;
    valueEl.select();
    document.execCommand("copy");

    store.doStopCoordCopy(x, y);
  },
  doStopCoordCopy: (x, y) => ({ dispatch, store }) => {
    const copyContainer = store.selectCoordsContainer();
    const msg = `Copied ${x}, ${y} to the clipboard.`;
    store.doSetCursor("default");

    dispatch({
      type: "COORD_COPIED",
      payload: {
        copyActive: false,
        container: null,
        notification: {
          title: "Coordinate Display",
          message: msg,
          level: "info",
        },
      },
    });

    copyContainer.remove(); //remove dynamically created node.
    store.doBasicToolbarDeactivate(); //close tool after copy.
  },
  doUpdateCoordInput: (e, label) => ({ dispatch, store }) => {
    e.preventDefault();
    e.stopPropagation();
    const latLonInput = store.selectCoordsLatLonInput();

    dispatch({
      type: "COORD_INPUT_UPDATED",
      payload: {
        latLonInput: {
          ...latLonInput,
          [`${label}`]: e.currentTarget.value,
        },
      },
    });
  },
  doCoordZoomTo: () => ({ dispatch, store }) => {
    const latLonInput = store.selectCoordsLatLonInput();
    const displayProjection = store.selectDisplayProjection();
    const x = Number(latLonInput.X);
    const y = Number(latLonInput.Y);

    if (isNaN(x) || isNaN(y)) {
      dispatch({
        type: "COORD_INPUT_INVALID",
        payload: {
          notification: {
            title: "Coordinate Display",
            message: "Enter valid number.",
            level: "danger",
          },
        },
      });
    } else {
      const center = transform([x, y], displayProjection, "EPSG:3857");
      store.doRenderCoordsOverlay(center, { x, y });
      store.doZoomToLocation(center, 13);
      store.doBasicToolbarDeactivate();
    }
  },
  selectCoordsValues: (state) => {
    return state.coordinateDisplay.values;
  },
  selectCoordsOverlay: (state) => {
    return state.coordinateDisplay.overlay;
  },
  selectCoordsContainer: (state) => {
    return state.coordinateDisplay.container;
  },
  selectCoordsCopyActive: (state) => {
    return state.coordinateDisplay.copyActive;
  },
  selectCoordsLatLonInput: (state) => {
    return state.coordinateDisplay.latLonInput;
  },
  reactCoordinateDisplayShouldInitialize: (state) => {
    if (state.coordinateDisplay._shouldInitialize)
      return { actionCreator: "doCoordsInitialize" };
  },
};
