import { get } from 'lodash';

export class WeightedSearch{
  static search<T>(term: string, fields: Array<string>, values: Array<T>):Array<T>{
    var normalizedTerm: string = term.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
    var lowerCaseTerm: string = term.toLowerCase();
    var lowerCaseNormalizedTerm: string = normalizedTerm.toLowerCase();

    var weightedValues: Array<{weight: number, value: T}> = [];

    for (let i = 0; i < values.length; i++) {
      const value = values[i];
      var weight: number = 0;

      //weighting score rules
      //+1: starts with normalized form
      //+1: contains normalized form
      //+1: whole word match with normalized form
      //+1: case insensitive starts with
      //+1: case insensitive contains
      //+1: case insensitive whole word match
      //+1: starts with original form
      //+1: contains original form
      //+1: whole word match with original form
      //+1: case sensitive starts with
      //+1: case sensitive contains
      //+1: case sensitive whole word match

      //+1: normalize value.field starts with
      //+1: normalize value.field contains
      //+1: normalize value.field whole word match
      //+1: normalize value.field lowercase starts with
      //+1: normalize value.field lowercase contains
      //+1: normalize value.field lowercase whole word match

      //+1: all normalized characters can be found in normalized value
      //+1: all normalized characters can be found in original value
      //+1: all characters can be found in normalized value
      //+1: all characters can be found in original value

      for(var field of fields){
        var fieldValue = get(value, field);

        if(fieldValue === undefined || fieldValue === null){
          continue;
        }

        var normalizedValue: string = fieldValue.toString().normalize("NFD").replace(/[\u0300-\u036f]/g, "");

        if(fieldValue.toString().startsWith(normalizedTerm)) weight++;
        if(fieldValue.toString().includes(normalizedTerm)) weight++;
        if(fieldValue.toString() == normalizedTerm) weight++;

        if(fieldValue.toString().toLowerCase().startsWith(lowerCaseNormalizedTerm)) weight++;
        if(fieldValue.toString().toLowerCase().includes(lowerCaseNormalizedTerm)) weight++;
        if(fieldValue.toString().toLowerCase() == lowerCaseNormalizedTerm) weight++;

        if(fieldValue.toString().toLowerCase().startsWith(lowerCaseTerm)) weight++;
        if(fieldValue.toString().toLowerCase().includes(lowerCaseTerm)) weight++;
        if(fieldValue.toString().toLowerCase() == lowerCaseTerm) weight++;

        if(fieldValue.toString().startsWith(term)) weight++;
        if(fieldValue.toString().includes(term)) weight++;
        if(fieldValue.toString() == term) weight++;

        if(normalizedValue.toLowerCase().startsWith(term)) weight++;
        if(normalizedValue.toLowerCase().includes(term)) weight++;
        if(normalizedValue.toLowerCase() == term) weight++;

        if(normalizedValue.startsWith(term)) weight++;
        if(normalizedValue.includes(term)) weight++;
        if(normalizedValue == term) weight++;

        if(normalizedValue.toLowerCase().startsWith(normalizedTerm)) weight++;
        if(normalizedValue.toLowerCase().includes(normalizedTerm)) weight++;
        if(normalizedValue.toLowerCase() == normalizedTerm) weight++;

        if(normalizedValue.startsWith(normalizedTerm)) weight++;
        if(normalizedValue.includes(normalizedTerm)) weight++;
        if(normalizedValue == normalizedTerm) weight++;

        // if(Array.from(normalizedTerm).every(c => normalizedValue.includes(c))) weight++;
        // if(Array.from(normalizedTerm).every(c => fieldValue.includes(c))) weight++;
        // if(Array.from(term).every(c => normalizedValue.includes(c))) weight++;
        if(Array.from(term).every(c => fieldValue.includes(c))) weight++;
      }

      if(weight > 0)
        weightedValues.push({weight, value})
    }

    weightedValues.sort((a, b) => b.weight - a.weight);

    return weightedValues.map(wv => wv.value);
  }
}