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

export class NodeLinkLayer extends CompositeLayer<CompositeLayerType> {
  static type = 'nodelink';
  private _layers: Record<string, Layer> = {};

  constructor(props: LayerProps) {
    super(props);
  }

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

  renderLayers() {
    const { data, settings, getNodeLocation, ml, graphMetadata } = this.props;
    const layerSettings = settings[NodeLinkLayer.type];

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

    graphMetadata.edges.labels.forEach((label: string) => {
      const layerId = `${label}-edges-line`;
      const edgeData = data.edges;

      this._layers[layerId] = new LineLayer({
        id: layerId,
        data: edgeData,
        visible: !layerSettings.edges[label].hidden,
        pickable: true,
        getWidth: layerSettings.edges[label].width,
        getSourcePosition: (d) => getNodeLocation(d.from),
        getTargetPosition: (d) => getNodeLocation(d.to),
        getColor: (d) => layerSettings.edges[d.label].color,
        extensions: [brushingExtension],
        brushingEnabled: layerSettings.enableBrushing,
      });
    });

    if (ml?.linkPrediction?.enabled) {
      this._layers['link_prediction'] = new LineLayer({
        id: 'link-prediction-layer',
        data: ml.linkPrediction.result,
        pickable: false,
        getWidth: 1,
        getSourcePosition: (d) => getNodeLocation(d.from),
        getTargetPosition: (d) => getNodeLocation(d.to),
        getColor: (d) => [0, 0, 0],
      });
    }

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

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

    const textLayerId = 'label-target';

    this._layers[textLayerId] = new TextLayer({
      id: textLayerId,
      data: data.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',
    });

    return Object.values(this._layers);
  }
}

NodeLinkLayer.layerName = 'NodeLink';