import xhr from "xhr";
import flatten from "lodash/flatten";
//import { Style, Fill, Stroke } from "ol/style";
let req = null;

export default {
  name: "legend",

  getReducer: () => {
    const initialData = {
      _shouldGetLegends: false,
      legendLayers: {},
      legendCanvases: {},
      loading: false,
    };

    return (state = initialData, { type, payload }) => {
      switch (type) {
        case "LAYERS_ORDER_UPDATED":
          return Object.assign({}, state, {
            _shouldGetLegends: true,
          });
        case "LEGEND_FETCH_START":
        case "LEGEND_LAYERS_UPDATED":
        case "LEGEND_LAYERS_UPDATE_ERROR":
        case "LEGEND_HAS_NO_VISIBLE_LAYERS":
        case "LEGEND_LOADED":
        case "LEGEND_CANVAS_ADDED":
          return Object.assign({}, state, payload);
        default:
          return state;
      }
    };
  },
  doFetchLegendInfo: (layers) => ({ dispatch, store }) => {
    if (req) req.abort();
    let legendLayers = store.selectLegendLayers();
    let legendCanvases = store.selectLegendCanvases();

    layers.forEach((lyr) => {
      const { url, type, layerList, uid, displayName } = lyr;
      legendCanvases[uid] = {
        displayName: displayName,
        canvas: [],
        widths: [],
        heights: [],
      };

      let src = url;

      switch (type) {
        case "ArcGIS":
          src = `${src}/legend?f=pjson`;
          break;
        case "ArcGISImage":
          src = `${src}/legend?bandIds=&renderingRule=&f=pjson`;
          break;
        case "EsriFeatureService":
          src = `${src}/${layerList}?f=pjson`;
          break;
        default:
          break;
      }
      req = xhr.get(src, (err, response, body) => {
        if (err || response.statusCode !== 200) {
          legendLayers[uid] = ["Legend not available!"];

          dispatch({
            type: "LEGEND_LAYERS_UPDATE_ERROR",
            payload: {
              legendLayers: legendLayers,
              legendCanvases: legendCanvases,
              loading: false,
            },
          });
        } else {
          try {
            const data = JSON.parse(body);
            if (type === "EsriFeatureService") {
              store.doGenerateEsriImages(data, lyr);
            } else {
              store.doGenerateArcImages(data, lyr);
            }
          } catch (err) {
            console.log(err);
            legendLayers[uid] = ["Legend not available!"];

            dispatch({
              type: "LEGEND_LAYERS_UPDATE_ERROR",
              payload: {
                legendLayers: legendLayers,
                legendCanvases: legendCanvases,
                loading: false,
              },
            });
          }
        }
      });

      // timeout after 60s.
      req.timeout = 60000;
    });
  },
  doGenerateArcImages: (data, lyr) => ({ dispatch, store }) => {
    const { uid, layerList, displayName } = lyr;
    let legendLayers = store.selectLegendLayers();
    let legendCanvases = store.selectLegendCanvases();
    const activeLayers = layerList.replace(/show:/g, "").split(",").map(Number);

    legendCanvases[uid] = {
      displayName: displayName,
      canvas: [],
      widths: [],
      heights: [],
    };

    const legends = data.layers.filter((item) => {
      return activeLayers.indexOf(item.layerId) !== -1;
    });
    const items = legends.map((legendLyr) => {
      return legendLyr.legend.map((legend) => {
        let img = new Image();
        img.addEventListener(
          "load",
          function () {
            let canvas = document.createElement("canvas");
            let ctx = canvas.getContext("2d");
            const labelWidth = Number(ctx.measureText(legend.label).width);

            //set canvas width & height
            canvas.width = Number(legend.width) + labelWidth + 4;
            canvas.height = legend.height;

            //store width & height for larger canvas calculation
            legendCanvases[uid].widths.push(canvas.width);
            legendCanvases[uid].heights.push(canvas.height);

            //set background
            ctx.fillStyle = "white";
            ctx.fillRect(0, 0, canvas.width, canvas.height);

            ctx.drawImage(img, 0, 0); //add image to canvas

            //add label to the right of image
            ctx.font = "10px Arial";
            ctx.fillStyle = "black";
            ctx.fillText(legend.label, legend.width + 2, legend.height / 2);
            legendCanvases[uid].canvas.push(canvas);

            dispatch({
              type: "LEGEND_CANVAS_ADDED",
              payload: {
                legendCanvases: legendCanvases,
                loading: false,
              },
            });
          },
          false
        );
        img.src = `data:${legend.contentType};base64,${legend.imageData}`;
        img.alt = `Style for ${legend.label}`;
        img.crossOrigin = "anonymous";
        img.title = legend.label;

        return img;
      });
    });
    legendLayers[uid] = flatten(items);

    dispatch({
      type: "LEGEND_LAYERS_UPDATED",
      payload: {
        legendLayers: legendLayers,
        loading: false,
      },
    });
  },

  doGenerateEsriImages: (data, lyr) => ({ dispatch, store }) => {
    const { uid, displayName } = lyr;
    let legendLayers = store.selectLegendLayers();
    let legendCanvases = store.selectLegendCanvases();
    const drawingInfo = data.drawingInfo;
    legendCanvases[uid] = {
      displayName: displayName,
      canvas: [],
      widths: [],
      heights: [],
    };
    legendLayers[uid] = [];

    switch (data.geometryType) {
      case "esriGeometryPolygon":
        if (
          drawingInfo.renderer.symbol &&
          drawingInfo.renderer.symbol.type === "esriSFS" &&
          drawingInfo.renderer.symbol.style === "esriSFSSolid"
        ) {
          let img = new Image();
          const outlineColor = drawingInfo.renderer.symbol.outline.color;
          const fillColor = drawingInfo.renderer.symbol.color;

          let canvas = document.createElement("canvas");
          let ctx = canvas.getContext("2d");

          canvas.width = 20;
          canvas.height = 20;

          //store width & height for larger canvas calculation
          legendCanvases[uid].widths.push(canvas.width);
          legendCanvases[uid].heights.push(canvas.height);

          // Draw polygon
          ctx.beginPath();
          ctx.lineWidth = "2";
          ctx.strokeStyle = `rgba(${outlineColor.join()})`;
          ctx.rect(0, 0, 20, 20);
          ctx.stroke();
          ctx.fillStyle = `rgba(${fillColor.join()})`;
          ctx.fillRect(1, 1, 18, 18);

          img.src = canvas.toDataURL(); //set src using data URI from canvas
          img.alt = `Style for ${displayName}`;
          img.crossOrigin = "anonymous";

          legendCanvases[uid].canvas.push(canvas);
          dispatch({
            type: "LEGEND_CANVAS_ADDED",
            payload: {
              legendCanvases: legendCanvases,
              loading: false,
            },
          });

          legendLayers[uid].push(img);
          dispatch({
            type: "LEGEND_LAYERS_UPDATED",
            payload: {
              legendLayers: legendLayers,
              loading: false,
            },
          });
        } else if (
          drawingInfo.renderer.type === "uniqueValue" &&
          drawingInfo.renderer.uniqueValueInfos
        ) {
          drawingInfo.renderer.uniqueValueInfos.forEach((val) => {
            let img = new Image();
            const outlineColor = val.symbol.outline.color;
            const fillColor = val.symbol.color;

            let canvas = document.createElement("canvas");
            let ctx = canvas.getContext("2d");
            const labelWidth = Number(ctx.measureText(val.label).width);

            //set canvas width & height
            canvas.width = 20 + labelWidth + 4;
            canvas.height = 20;

            //store width & height for larger canvas calculation
            legendCanvases[uid].widths.push(canvas.width);
            legendCanvases[uid].heights.push(canvas.height);

            // Draw polygon
            ctx.beginPath();
            ctx.lineWidth = "2";
            ctx.strokeStyle = `rgba(${outlineColor.join()})`;
            ctx.rect(0, 0, 20, 20);
            ctx.stroke();
            ctx.fillStyle = `rgba(${fillColor.join()})`;
            ctx.fillRect(1, 1, 18, 18);

            //add label to the right of image
            ctx.font = "10px Arial";
            ctx.fillStyle = "black";
            ctx.fillText(val.label, 22, canvas.height / 2);

            //set img attributes
            img.src = canvas.toDataURL();
            img.alt = `Style for ${displayName}`;
            img.crossOrigin = "anonymous";

            legendCanvases[uid].canvas.push(canvas);
            dispatch({
              type: "LEGEND_CANVAS_ADDED",
              payload: {
                legendCanvases: legendCanvases,
                loading: false,
              },
            });

            legendLayers[uid].push(img);
          });
          dispatch({
            type: "LEGEND_LAYERS_UPDATED",
            payload: {
              legendLayers: legendLayers,
              loading: false,
            },
          });
        }
        break;
      case "esriGeometryPolyline":
        if (
          drawingInfo.renderer.symbol &&
          drawingInfo.renderer.symbol.type === "esriSLS" &&
          drawingInfo.renderer.symbol.style === "esriSLSSolid"
        ) {
          let img = new Image();
          let canvas = document.createElement("canvas");
          let ctx = canvas.getContext("2d");
          const lineColor = drawingInfo.renderer.symbol.color;

          canvas.width = 20;
          canvas.height = 20;

          //store width & height for larger canvas calculation
          legendCanvases[uid].widths.push(canvas.width);
          legendCanvases[uid].heights.push(canvas.height);

          // Draw line
          ctx.beginPath();
          ctx.strokeStyle = `rgba(${lineColor.join()})`;
          ctx.moveTo(0, 0);
          ctx.lineTo(20, 20);
          ctx.stroke();

          //set img attributes
          img.src = canvas.toDataURL(); //set src using data URI from canvas
          img.alt = `Style for ${displayName}`;
          img.crossOrigin = "anonymous";

          legendCanvases[uid].canvas.push(canvas);
          dispatch({
            type: "LEGEND_CANVAS_ADDED",
            payload: {
              legendCanvases: legendCanvases,
              loading: false,
            },
          });

          legendLayers[uid].push(img);
          dispatch({
            type: "LEGEND_LAYERS_UPDATED",
            payload: {
              legendLayers: legendLayers,
              loading: false,
            },
          });
        } else if (
          drawingInfo.renderer.type === "uniqueValue" &&
          drawingInfo.renderer.uniqueValueInfos
        ) {
          drawingInfo.renderer.uniqueValueInfos.forEach((val) => {
            let img = new Image();

            let canvas = document.createElement("canvas");
            let ctx = canvas.getContext("2d");
            const labelWidth = Number(ctx.measureText(val.label).width);
            const lineColor = val.symbol.color;

            //set canvas width & height
            canvas.width = 20 + labelWidth + 4;
            canvas.height = 20;

            //store width & height for larger canvas calculation
            legendCanvases[uid].widths.push(canvas.width);
            legendCanvases[uid].heights.push(canvas.height);

            // Draw line
            ctx.beginPath();
            ctx.strokeStyle = `rgba(${lineColor.join()})`;
            ctx.moveTo(0, 0);
            ctx.lineTo(20, 20);
            ctx.stroke();

            //add label to the right of image
            ctx.font = "10px Arial";
            ctx.fillStyle = "black";
            ctx.fillText(val.label, 22, canvas.height / 2);

            //set img attributes
            img.src = canvas.toDataURL();
            img.alt = `Style for ${displayName}`;
            img.crossOrigin = "anonymous";

            legendCanvases[uid].canvas.push(canvas);
            dispatch({
              type: "LEGEND_CANVAS_ADDED",
              payload: {
                legendCanvases: legendCanvases,
                loading: false,
              },
            });

            legendLayers[uid].push(img);
          });
          dispatch({
            type: "LEGEND_LAYERS_UPDATED",
            payload: {
              legendLayers: legendLayers,
              loading: false,
            },
          });
        }
        break;
      case "esriGeometryPoint":
        if (drawingInfo.renderer.symbol.type === "esriPMS") {
          let img = new Image();
          img.src = `data:image/png;base64,${data.drawingInfo.renderer.symbol.imageData}`;
          img.addEventListener(
            "load",
            function () {
              let canvas = document.createElement("canvas");
              let ctx = canvas.getContext("2d");

              canvas.width = drawingInfo.renderer.symbol.width;
              canvas.height = drawingInfo.renderer.symbol.height;

              //store width & height for larger canvas calculation
              legendCanvases[uid].widths.push(canvas.width);
              legendCanvases[uid].heights.push(canvas.height);

              //set background
              ctx.fillStyle = "white";
              ctx.fillRect(0, 0, canvas.width, canvas.height);

              ctx.drawImage(img, 0, 0); //add image to canvas

              legendCanvases[uid].canvas.push(canvas);

              dispatch({
                type: "LEGEND_CANVAS_ADDED",
                payload: {
                  legendCanvases: legendCanvases,
                  loading: false,
                },
              });
            },
            false
          );

          img.alt = `Style for ${displayName}`;
          img.crossOrigin = "anonymous";
          legendLayers[uid] = [img]; //TODO: Update to possibly push multiple images into array
          dispatch({
            type: "LEGEND_LAYERS_UPDATED",
            payload: {
              legendLayers: legendLayers,
            },
          });
        } else if (drawingInfo.renderer.symbol.type === "esriSMS") { 
            let img = new Image();
            const outlineColor = drawingInfo.renderer.symbol.outline.color;
            const outlineWidth = drawingInfo.renderer.symbol.outline.width;
            const fillColor = drawingInfo.renderer.symbol.color;
            const size = drawingInfo.renderer.symbol.size;

            let canvas = document.createElement("canvas");
            let ctx = canvas.getContext("2d");

            canvas.width = 20;
            canvas.height = 20;

            legendCanvases[uid].widths.push(canvas.width);
            legendCanvases[uid].heights.push(canvas.height);

            // circle
            ctx.beginPath();
            ctx.strokeStyle = `rgba(${outlineColor.join()})`;
            ctx.lineWidth = outlineWidth;
            ctx.arc(size, size, size/1.5, 0, Math.PI * 2);
            ctx.fillStyle = `rgba(${fillColor.join()})`;
            ctx.fill();
            ctx.stroke();

            img.src = canvas.toDataURL(); //set src using data URI from canvas
            img.alt = `Style for ${displayName}`;
            img.crossOrigin = "anonymous";

            legendCanvases[uid].canvas.push(canvas);
            dispatch({
              type: "LEGEND_CANVAS_ADDED",
              payload: {
                legendCanvases: legendCanvases,
                loading: false,
              },
            });

            legendLayers[uid].push(img);
            dispatch({
              type: "LEGEND_LAYERS_UPDATED",
              payload: {
                legendLayers: legendLayers,
                loading: false,
              },
            });
        } else {
          legendLayers[uid] = ["Legend not available!"];
          dispatch({
            type: "LEGEND_LAYERS_UPDATE_ERROR",
            payload: {
              legendLayers: legendLayers,
              legendCanvases: legendCanvases,
              loading: false,
            },
          });
        }
        break;
      default:
        break;
    }
  },
  doFetchLegendImages: () => ({ dispatch, store }) => {
    dispatch({
      type: "LEGEND_FETCH_START",
      payload: {
        _shouldGetLegends: false,
        loading: true,
      },
    });

    const visibleLayers = store.selectVisibleLayers();
    let legendLayers = store.selectLegendLayers();
    let legendCanvases = store.selectLegendCanvases();
    let queuedLayers = [];

    visibleLayers.forEach((layer) => {
      //check if layer already added legendLayers object.
      if (!legendLayers.hasOwnProperty(layer.uid)) {
        switch (layer.type) {
          case "ArcGIS":
          case "ArcGISImage":
          case "EsriFeatureService":
            if(layer.styleFn  && layer.type === "EsriFeatureService") {
              
              legendCanvases[layer.uid] = {
                displayName: layer.displayName,
                canvas: [],
                widths: [],
                heights: [],
              };
              legendLayers[layer.uid] = [];
            
              //Get canvases and images for legend
              let legendFunction = eval(layer.styleFn)[1];
              let legendItems = legendFunction();

              legendItems.forEach((item) => {
                item.image.alt = `Style for ${layer.displayName}`;
                legendCanvases[layer.uid].widths.push(item.canvas.width);
                legendCanvases[layer.uid].heights.push(item.canvas.height);
                legendCanvases[layer.uid].canvas.push(item.canvas);
                legendLayers[layer.uid].push(item.image);

                dispatch({
                  type: "LEGEND_CANVAS_ADDED",
                  payload: {
                    legendCanvases: legendCanvases,
                    loading: false,
                  },
                });
              });
            
              dispatch({
                type: "LEGEND_LAYERS_UPDATED",
                payload: {
                  legendLayers: legendLayers,
                },
              });
            }
            else {
              queuedLayers.push(layer);
            }
            break;
          case "WMS":
            legendCanvases[layer.uid] = {
              displayName: layer.displayName,
              canvas: [],
              widths: [],
              heights: [],
            };
            let activeLayers = layer.layerList.replace(/ /g, "").split(",");
            const images = activeLayers.map((lyr, i) => {
              let img = new Image();
              img.addEventListener(
                "load",
                function () {
                  let canvas = document.createElement("canvas");
                  let ctx = canvas.getContext("2d");

                  //set canvas width & height
                  canvas.width = Number(img.width) + 2;
                  canvas.height = img.height;

                  //store width & height for larger canvas calculation
                  legendCanvases[layer.uid].widths.push(canvas.width);
                  legendCanvases[layer.uid].heights.push(canvas.height);

                  //set background
                  ctx.fillStyle = "white";
                  ctx.fillRect(0, 0, canvas.width, canvas.height);

                  ctx.drawImage(img, 0, 0); //add image to canvas

                  legendCanvases[layer.uid].canvas.push(canvas);

                  dispatch({
                    type: "LEGEND_CANVAS_ADDED",
                    payload: {
                      legendCanvases: legendCanvases,
                      loading: false,
                    },
                  });
                },
                false
              );
              let legendParams = `service=WMS&version=1.1.1&request=GetLegendGraphic&format=image/png&sld_version=1.1.0&layer=${lyr}`;
              if (layer.url.indexOf(".map") !== -1) {
                img.src = `${layer.url}&${legendParams}`;
              } else {
                img.src = `${layer.url}?${legendParams}`;
              }

              img.alt = `Style for ${layer.displayName}`;
              img.crossOrigin = "anonymous";

              return img;
            });
            legendLayers[layer.uid] = images;

            dispatch({
              type: "LEGEND_LAYERS_UPDATED",
              payload: {
                legendLayers: legendLayers,
              },
            });
            break;
          case "LocalVector":
          default:
            legendCanvases[layer.uid] = {
              displayName: layer.displayName,
              canvas: [],
              widths: [],
              heights: [],
            };
            if (layer.src) {
              let img = new Image();
              img.addEventListener(
                "load",
                function () {
                  let canvas = document.createElement("canvas");
                  let ctx = canvas.getContext("2d");

                  //set canvas width & height
                  canvas.width = Number(img.width) + 2;
                  canvas.height = img.height;

                  //store width & height for larger canvas calculation
                  legendCanvases[layer.uid].widths.push(canvas.width);
                  legendCanvases[layer.uid].heights.push(canvas.height);

                  //set background
                  ctx.fillStyle = "white";
                  ctx.fillRect(0, 0, canvas.width, canvas.height);

                  ctx.drawImage(img, 0, 0); //add image to canvas
                  
                  legendCanvases[layer.uid].canvas.push(canvas);

                  dispatch({
                    type: "LEGEND_CANVAS_ADDED",
                    payload: {
                      legendCanvases: legendCanvases,
                      loading: false,
                    },
                  });
                },
                false
              );
              img.src = layer.src;
              img.alt = `Style for ${layer.displayName}`;
              img.crossOrigin = "anonymous";
              legendLayers[layer.uid] = [img];
              dispatch({
                type: "LEGEND_LAYERS_UPDATED",
                payload: {
                  legendLayers: legendLayers,
                },
              });
            } else {
              legendLayers[layer.uid] = ["Legend not available!"];
              dispatch({
                type: "LEGEND_LAYERS_UPDATE_ERROR",
                payload: {
                  legendLayers: legendLayers,
                  legendCanvases: legendCanvases,
                  loading: false,
                },
              });
            }
            break;
        }
      } else {
        dispatch({
          type: "LEGEND_LOADED",
          payload: {
            loading: false,
          },
        });
      }
    });

    if (queuedLayers.length) store.doFetchLegendInfo(queuedLayers);
    if (!visibleLayers.length) {
      dispatch({
        type: "LEGEND_HAS_NO_VISIBLE_LAYERS",
        payload: {
          loading: false,
        },
      });
    }
  },
  selectLegendLayers: (state) => {
    return state.legend.legendLayers;
  },
  selectLegendCanvases: (state) => {
    return state.legend.legendCanvases;
  },
  selectLegendLoading: (state) => {
    return state.legend.loading;
  },
  reactLegendShouldGetLegend: (state) => {
    if (state.legend._shouldGetLegends)
      return { actionCreator: "doFetchLegendImages" };
  },
};
