package it.mice.voila.runtime.security.encoders;

import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
import org.springframework.security.crypto.password.MessageDigestPasswordEncoder;

import javax.xml.bind.DatatypeConverter;

public class PBEWithMD5AndDESPasswordEncryption
		implements PasswordDecoder, org.springframework.security.crypto.password.PasswordEncoder {

//	@Bean
//	public org.springframework.security.crypto.password.PasswordEncoder passwordEncoder() {
//		// Mappa di encoder con i rispettivi ID
//		Map<String, org.springframework.security.crypto.password.PasswordEncoder> encoders = new HashMap<>();
//		// Aggiungi l'encoder bcrypt
//		// encoders.put("bcrypt", new BCryptPasswordEncoder());
//		// Aggiungi il tuo encoder personalizzato
//		encoders.put("pbe", new PBEWithMD5AndDESPasswordEncryption()); // Imposta bcrypt come encoder predefinito
//																		// (defaultIdForEncode)return new
//																		// DelegatingPasswordEncoder("bcrypt",
//																		// encoders); }
//		return new DelegatingPasswordEncoder("pbe", encoders);
//	}

	// public PBEWithMD5AndDESPasswordEncryption() {
//		super("pbe", );
//	}

	private static final byte[] SALT = { (byte) 0xde, (byte) 0x33, (byte) 0x15, (byte) 0x12, (byte) 0xde, (byte) 0x33,
			(byte) 0x16, (byte) 0x12, };

	//@Bean
	public String decodePassword(String encPass, Object password) {
		try {
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
			SecretKey key = keyFactory.generateSecret(new PBEKeySpec(password.toString().toCharArray()));
			Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
			pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
			return new String(pbeCipher.doFinal(base64Decode(encPass)), "UTF-8");
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public String encodePassword(String rawPass, Object password) {
		try {
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
			SecretKey key = keyFactory.generateSecret(new PBEKeySpec(password.toString().toCharArray()));
			Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
			pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
			return "{pbe}" + base64Encode(pbeCipher.doFinal(rawPass.getBytes("UTF-8")));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	private static String base64Encode(byte[] bytes) {
		return DatatypeConverter.printBase64Binary(bytes);
//        return Base64.getEncoder().encodeToString(bytes);
	}

	private static byte[] base64Decode(String property) {
		return DatatypeConverter.parseBase64Binary(property);
//        return Base64.getDecoder().decode(property);
	}

//	public boolean isPasswordValid(String encPass, String rawPass, Object salt) {
//		String rawPassEncoded = encodePassword(rawPass, salt);
//		return encPass.equals(rawPassEncoded);
//	}

	public boolean isPasswordValid(String encPass, String rawPass, Object salt) {
		// Verifica che l'ID corrisponda a quello che hai usato nell'encoding
		if (encPass.startsWith("{pbe}")) {
			encPass = encPass.substring(5);
			// Rimuovi l'ID prima della verifica
			String rawPassEncoded = encodePassword(rawPass, salt);
			return encPass.equals(rawPassEncoded);
		}
		return false;
	}

	private final static String sale = "enfldilardo05lksdsgm";
	
	@Override
	public String encode(CharSequence rawPass) {
		try {
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
			SecretKey key = keyFactory.generateSecret(new PBEKeySpec(sale.toCharArray()));
			Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
			pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
			return base64Encode(pbeCipher.doFinal(rawPass.toString().getBytes("UTF-8")));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	@Override
	public boolean matches(CharSequence rawPass, String encPass) {
		String rawPassEncoded = encode(rawPass);
		return encPass.equals(rawPassEncoded);
	}
}
