import { MinimalPerfectHash } from '../graph/PerfectHash.js';
import { WaveletAdjacency } from '../graph/WaveletAdjacency.js';

export class CondensedGraphFinalize {
  constructor(graph) {
    this.graph = graph;
  }

  finalizePerfectHash(options = {}) {
    if (this.graph._mphEnabled) return;
    const keys = [];
    const values = [];
    for (let i = 0; i < this.graph.nodeIds.length; i++) {
      const key = this.graph.getNodeKey(i);
      if (key === undefined) continue;
      keys.push(key);
      values.push(i);
    }
    if (!keys.length) return;
    this.graph._mph = MinimalPerfectHash.build(keys, values, options, values);
    this.graph._mphEnabled = !!this.graph._mph;
  }

  finalizeWaveletAdjacency(options = {}) {
    this.graph._dropAdjacencyList = options.dropAdjacencyList !== undefined
      ? options.dropAdjacencyList
      : this.graph._dropAdjacencyList;
    const edgeCount = this.graph.edgeIndex;
    if (!edgeCount) {
      if (this.graph._dropAdjacencyList) {
        this.graph.edgeSrcIds = new Int32Array(0);
        this.graph.edgeRelIds = new Int32Array(0);
        this.graph.edgeDstIds = new Int32Array(0);
        this.graph.edgePossibilityBits = new Uint16Array(0);
        this.graph.edgeReliabilityBits = new Uint16Array(0);
        this.graph.adjacency = null;
        this.graph.nodeHeads = null;
      }
      return;
    }

    const relationCount = this.graph.nextRelationId;
    const relDsts = new Array(relationCount);
    const relEdges = new Array(relationCount);

    for (let edgeIdx = 0; edgeIdx < edgeCount; edgeIdx++) {
      const baseIdx = edgeIdx * 6;
      const srcId = this.graph.adjacency[baseIdx + 0];
      const relId = this.graph.adjacency[baseIdx + 1];
      const dstId = this.graph.adjacency[baseIdx + 2];

      if (!relDsts[relId]) {
        relDsts[relId] = new Array(this.graph.numNodes);
        relEdges[relId] = new Array(this.graph.numNodes);
        for (let n = 0; n < this.graph.numNodes; n++) {
          relDsts[relId][n] = [];
          relEdges[relId][n] = [];
        }
      }

      relDsts[relId][srcId].push(dstId);
      relEdges[relId][srcId].push(edgeIdx);
    }

    this.graph._waveletByRelId = new Array(relationCount);
    for (let relId = 0; relId < relationCount; relId++) {
      if (relDsts[relId]) {
        this.graph._waveletByRelId[relId] = WaveletAdjacency.build(this.graph.numNodes, relDsts[relId], relEdges[relId]);
      }
    }

    this.graph._waveletAll = null;

    if (this.graph._dropAdjacencyList) {
      const edgeCount = this.graph.edgeIndex;
      const srcIds = new Int32Array(edgeCount);
      const relIds = new Int32Array(edgeCount);
      const dstIds = new Int32Array(edgeCount);
      const possBits = new Uint16Array(edgeCount);
      const relBits = new Uint16Array(edgeCount);

      for (let edgeIdx = 0; edgeIdx < edgeCount; edgeIdx++) {
        const baseIdx = edgeIdx * 6;
        srcIds[edgeIdx] = this.graph.adjacency[baseIdx + 0];
        relIds[edgeIdx] = this.graph.adjacency[baseIdx + 1];
        dstIds[edgeIdx] = this.graph.adjacency[baseIdx + 2];
        possBits[edgeIdx] = this.graph.adjacency[baseIdx + 3] & 0xffff;
        relBits[edgeIdx] = this.graph.adjacency[baseIdx + 4] & 0xffff;
      }

      this.graph.edgeSrcIds = srcIds;
      this.graph.edgeRelIds = relIds;
      this.graph.edgeDstIds = dstIds;
      this.graph.edgePossibilityBits = possBits;
      this.graph.edgeReliabilityBits = relBits;

      this.graph.adjacency = null;
      this.graph.nodeHeads = null;
    }
  }
}
