package de.iteratec.karate.login.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.time.LocalDate;
import java.util.Base64;

/**
 * Hashing service, that helps you to convert a string to an pseudonymized string.
 * <p>
 * The algorithm is based on an external configured pepper and an internal monthly rolled over salt.
 * <p>
 * <strong>Important:</strong> This service relies mainly on the entropy of the pepper!
 */
@Service
public class HashingService {

    private String pepper;
    private String salt;
    private MessageDigest digest;

    @Autowired
    public HashingService(@Value("${karate.hashing.pepper}") String pepperValue) {
        try {
            pepper = pepperValue;
            salt = getSalt();
            digest = MessageDigest.getInstance("SHA-256");
            ensureInitOfPepper();
        } catch (Exception e) {
            //Wrap Exception into RuntimeException...
            throw new IllegalStateException("HashingService not correctly intialized!", e);
        }
    }

    private void ensureInitOfPepper() {
        if (pepper == null || pepper.isEmpty()) {
            throw new IllegalStateException("The hashing pepper is not configured!");
        }
    }

    private String getSalt() {
        LocalDate currentDate = LocalDate.now();
        int month = currentDate.getMonthValue();
        int year = currentDate.getYear();
        return month + "-" + year;
    }

    /**
     * Converts an input to a pseudonymized string. Based on an SHA-256 algorithm and salt.
     *
     * @param input clear text to pseudonymize
     *
     * @return Base64 encoded pseudonymized string.
     */
    public String pseudonymize(String input) {
        String saltedInput = input + salt + pepper;
        byte[] digest = this.digest.digest(saltedInput.getBytes(StandardCharsets.UTF_8));
        return convertToBase64String(digest);
    }

    private String convertToBase64String(byte[] digest) {
        return new String(Base64.getEncoder().encode(digest));
    }

}