import { Injectable } from '@severo-tech/injection-decorator';
import { combinations } from '@severo-tech/combinatorial-analysis';
// import cache from 'node-cache-decorator';

export interface ICombinationsValue {
  id: string;
  value: number | string;
}

@Injectable()
export class CombinationsUtil {
  // @cache('CombinationsUtil.byValue', 60 * 60)
  public byValue<T extends ICombinationsValue>(list: T[], target: number, resolveIfDirectMatch = false): T[][] {
    const innerList = list
      .map((el: T): T & { value: number } => ({ ...el, value: +el.value }));

    if (resolveIfDirectMatch) {
      const directMatches = innerList.filter((el: T): boolean => el.value === target);

      if (directMatches.length) {
        return directMatches.map((el: T): T[] => [el]);
      }
    }

    return combinations.byValue(innerList, target);

    // const sortedList = innerList.sort((a: T, b: T): number => +b.value - +a.value);
    // const combinations = this.findCombination([], sortedList, target);

    // return combinations.filter((el: T[]): boolean => el.length > 0);
  }

  private findCombination<T extends { value: number }>(current: T[], remaining: T[], remainingValue: number): T[][] {
    if (remainingValue === 0) {
      return [current];
    }

    if (remainingValue < 0) {
      return [];
    }

    const innerRemaining = remaining.filter((el: T): boolean => el.value <= remainingValue);
    if (innerRemaining.length === 0) {
      return [];
    }

    const sumOfRemaining = innerRemaining.reduce((total: number, el: T): number => +(total + el.value).toFixed(2), 0);
    if (sumOfRemaining < remainingValue) {
      return [];
    }

    const invoice = innerRemaining[0];
    const invoiceValue = invoice.value;

    const includeNote = this.findCombination(
      [...current, invoice],
      innerRemaining.slice(1),
      +(remainingValue - invoiceValue).toFixed(2),
    );

    const excludeNote = this.findCombination(
      current,
      innerRemaining.slice(1),
      remainingValue,
    );

    return [...includeNote, ...excludeNote];
  }
}
