import React from 'react';
import { CompositeLayer } from 'deck.gl';
import { IconLayer, LineLayer, ScatterplotLayer, TextLayer } from '@deck.gl/layers';
import { LayerProps } from '../../mapvis.types';
import { BrushingExtension, CollisionFilterExtension } from '@deck.gl/extensions';
import { Edge, Node } from '@graphpolaris/shared/lib/data-access';
import { createIcon } from './shapeFactory';

export class NodeLinkLayer extends CompositeLayer<LayerProps> {
  static type = 'NodeLink';

  updateState({ changeFlags }: { changeFlags: any }) {
    return changeFlags.propsOrDataChanged || changeFlags.somethingChanged;
  }

  renderLayers() {
    const { graph, config, getNodeLocation, selected, setLayerIds, metaData } = this.props;

    const layers = [];
    const layerIds = [];

    const brushingExtension = new BrushingExtension();
    const collisionFilter = new CollisionFilterExtension();

    metaData.nodes.labels.forEach((label: string) => {
      const layerId = `${label}-nodes-scatterplot`;
      layerIds.push(layerId);

      layers.push(
        new IconLayer({
          id: layerId,
          visible: !config[label].hidden,
          data: graph.nodes.filter((node: Node) => node.label === label),
          pickable: true,
          getColor: (d) => [200, 140, 0],
          getSize: (d: any) => config[label].size,
          getPosition: (d: any) => getNodeLocation(d._id),
          getIcon: (d: any) => {
            return {
              url: createIcon(config[label].shape ?? 'circle', config[label].color),
              width: 24,
              height: 24,
            };
          },
          mask: true,
        }),
      );
    });

    metaData.edges.labels.forEach((label: string) => {
      const layerId = `${label}-edges-line`;
      layerIds.push(layerId);

      const edgeData =
        selected.length > 0 ? graph.edges.filter((edge: Edge) => selected.includes(edge.from) || selected.includes(edge.to)) : graph.edges;

      layers.push(
        new LineLayer({
          id: layerId,
          data: edgeData,
          visible: !config[label]?.hidden,
          pickable: true,
          getWidth: (d: any) => config[label].width,
          getSourcePosition: (d: any) => getNodeLocation(d.from),
          getTargetPosition: (d: any) => getNodeLocation(d.to),
          getColor: (d: any) => config[d.label].color,
          radiusScale: 3000,
          brushingEnabled: config.enableBrushing,
          extensions: [brushingExtension],
        }),
      );
    });

    const textLayerId = 'label-target';
    layerIds.push(textLayerId);

    layers.push(
      new TextLayer({
        id: textLayerId,
        data: graph.nodes,
        getPosition: (d: any) => getNodeLocation(d._id),
        getText: (d: any) => d.id,
        getSize: 15,
        visible: true,
        getAlignmentBaseline: 'top',
        background: true,
        getPixelOffset: [10, 10],
        extensions: [collisionFilter],
        collisionEnabled: true,
        getCollisionPriority: (d: any) => d.id,
        collisionTestProps: { sizeScale: 10 },
        getRadius: 10,
        radiusUnits: 'pixels',
        collisionGroup: 'text',
      }),
    );

    setLayerIds(layerIds);

    return layers;
  }
}

NodeLinkLayer.layerName = 'NodeLink';