package de.ivu.elect.business.system.control;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;

import de.ivu.elect.util.ElectRandom;

public class ElectPasswordGenerator {

  private final int laenge;

  private final String[] characterClasses;

  private final String passwordRegex;

  public ElectPasswordGenerator(int laenge, String[] characterClasses) {
    this(laenge, characterClasses, null);
  }

  public ElectPasswordGenerator(int laenge, String[] characterClasses, String passwordRegex) {
    this.laenge = laenge;
    this.characterClasses = characterClasses;
    this.passwordRegex = passwordRegex;
  }

  public String createPasswort(int maxTries) {
    return IntStream.range(0, maxTries).mapToObj(i -> generatePasswort())
        .filter(passwort -> StringUtils.isBlank(passwordRegex) || passwort.matches(passwordRegex)).findFirst().orElse("");
  }

  String generatePasswort() {
    StringBuilder sb = new StringBuilder(laenge);
    for (String characterClass : characterClasses) {
      sb.append(getRandomCharacter(1, characterClass)); // mind. 1 Zeichen aus jeder Zeichenklasse
    }
    String allCharacters = StringUtils.join(characterClasses);
    sb.append(getRandomCharacter(laenge - characterClasses.length, allCharacters));
    return shuffle(sb.toString());
  }

  private String getRandomCharacter(int anzahl, String alphabet) {
    // ELECTVAPP-1366
    char[] chars = alphabet.toCharArray();
    return RandomStringUtils.random(anzahl, 0, chars.length, false, false, chars, ElectRandom.getRandom());
  }

  /**
   * Cf. https://stackoverflow.com/a/51364075
   */
  private String shuffle(String string) {
    List<Character> list = string.chars().mapToObj(c -> (char) c).collect(Collectors.toList());
    Collections.shuffle(list);
    StringBuilder sb = new StringBuilder();
    list.forEach(sb::append);
    return sb.toString();
  }

}
