import { visualizationColors } from 'config';
import { GraphType, LinkType, NodeType } from '../types';

/**
 * Colour is a function that takes a string of a number and returns a number of a color out of the d3 color scheme.
 * @param num Num is the input string representing a number of a colorgroup.
 * @returns {number} A number corresponding to a color in the d3 color scheme.
 */
export function nodeColor(num: number) {
  // num = num % 4;
  // const col = '#000000';
  //let entityColors = Object.values(visualizationColors.GPSeq.colors[9]);
  const col = visualizationColors.GPCat.colors[14][num % visualizationColors.GPCat.colors[14].length];
  return binaryColor(col);
}

export function nodeColorHex(num: number) {
  // num = num % 4;
  // const col = '#000000';

  //let entityColors = Object.values(visualizationColors.GPSeq.colors[9]);
  const col = visualizationColors.GPCat.colors[14][num % visualizationColors.GPCat.colors[14].length];
  return col;
}

export function binaryColor(color: string) {
  return Number('0x' + color.replace('#', ''));
}

export function uniq<T>(items: T[]): T[] {
  return Array.from(new Set<T>(items));
}

/**
 * Converts a hexadecimal color code to a number.
 *
 * @param hexColor The hexadecimal color code to convert.
 * @returns The converted number.
 */
export function hexToNumber(hexColor: string) {
  return parseInt(hexColor.replace('#', ''), 16);
}

export function hslStringToHex(hsl: string) {
  // Extract h, s, l from the input string

  const match = hsl.match(/\d+/g);
  if (!match) return '#000000';
  let [h, s, l] = match.map(Number);

  l /= 100;
  const a = (s * Math.min(l, 1 - l)) / 100;
  const f = (n: number) => {
    const k = (n + h / 30) % 12;
    const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
    return Math.round(255 * color)
      .toString(16)
      .padStart(2, '0'); // Convert to Hex and ensure 2 digits
  };
  return `#${f(0)}${f(8)}${f(4)}`;
}

/**
 * Used when you select nodes.
 * The highlight is drawn in ticked.
 * @param nodes The nodes you want to related edges to.
 * @returns {LinkType[]} All the links related to all the nodes
 */
export const getRelatedLinks = (graph: GraphType, nodes: NodeType[], jaccardThreshold: number): LinkType[] => {
  const relatedLinks: LinkType[] = [];
  Object.keys(graph.links).forEach((id) => {
    const link = graph.links[id];
    const { source, target } = link;
    if (isLinkVisible(link, jaccardThreshold)) {
      nodes.forEach((node: NodeType) => {
        if (source == node._id || target == node._id || source == node._id || target == node._id) {
          relatedLinks.push(link);
        }
      });
    }
  });
  return relatedLinks;
};

/**
 * Checks wheter a link is visible.
 * This is used for highlighting nodes.
 * @param link The link you want to check wheter it's visable or not
 * @returns {boolean}
 */
export function isLinkVisible(link: LinkType, jaccardThreshold: number): boolean {
  //About the next line, If you don't do this here but lets say in the constructor it errors. So far no performance issues where noticed.
  if (link.mlEdge) {
    if (link.value > jaccardThreshold) {
      return true;
    }
  } else return true;
  return false;
}