package kr.co.uplus.ez.common.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

@Slf4j
public class EncryptionUtil {

	// 파일구분자
	static final char FILE_SEPARATOR = File.separatorChar;

	static final int BUFFER_SIZE = 1024;

	/**
	 * 비밀번호를 암호화하는 기능(복호화가 되면 안되므로 SHA-256 인코딩 방식 적용)
	 *
	 * @param password 암호화될 패스워드
	 * @param id       salt로 사용될 사용자 ID 지정
	 * @return
	 * @throws Exception
	 */
	public static String encryptPassword(String password, String id) throws Exception {

		if (password == null)
			return "";
		if (id == null)
			return "";

		byte[] hashValue = null;

		MessageDigest md = MessageDigest.getInstance("SHA-256");

		md.reset();
		md.update(id.getBytes());

		hashValue = md.digest(password.getBytes());

		return new String(Base64.encodeBase64(hashValue));
	}

	/**
	 * 비밀번호를 암호화하는 기능(복호화가 되면 안되므로 SHA-256 인코딩 방식 적용)
	 *
	 * @param data 암호화할 비밀번호
	 * @param salt Salt
	 * @return 암호화된 비밀번호
	 * @throws Exception
	 */
	public static String encryptPassword(String data, byte[] salt) throws Exception {

		if (data == null) {
			return "";
		}

		byte[] hashValue = null; // 해쉬값

		MessageDigest md = MessageDigest.getInstance("SHA-256");

		md.reset();
		md.update(salt);

		hashValue = md.digest(data.getBytes());

		return new String(Base64.encodeBase64(hashValue));
	}

	/**
	 * 비밀번호를 암호화된 패스워드 검증(salt가 사용된 경우만 적용).
	 *
	 * @param data    원 패스워드
	 * @param encoded 해쉬처리된 패스워드(Base64 인코딩)
	 * @return
	 * @throws Exception
	 */
	public static boolean checkPassword(String data, String encoded, byte[] salt) throws Exception {
		byte[] hashValue = null; // 해쉬값

		MessageDigest md = MessageDigest.getInstance("SHA-256");

		md.reset();
		md.update(salt);
		hashValue = md.digest(data.getBytes());

		return MessageDigest.isEqual(hashValue, Base64.decodeBase64(encoded.getBytes()));
	}

	public static boolean checkPassword(String data, String encoded, String id) throws Exception {
		byte[] hashValue = null; // 해쉬값

		MessageDigest md = MessageDigest.getInstance("SHA-256");

		md.reset();
		md.update(id.getBytes());
		hashValue = md.digest(data.getBytes());

		return MessageDigest.isEqual(hashValue, Base64.decodeBase64(encoded.getBytes()));
	}

	/**
	 * SHA1.
	 *
	 * @param message
	 * @return
	 * @throws Exception
	 * @throws NoSuchAlgorithmException
	 * @throws InvalidKeyException
	 */
	public static String getSHA1Encrypt(String message)
			throws Exception, NoSuchAlgorithmException, InvalidKeyException {
		StringBuffer hexString = new StringBuffer();

		MessageDigest md = MessageDigest.getInstance("SHA-1");

		byte[] hash = md.digest(message.getBytes("UTF-8"));

		for (int i = 0; i < hash.length; i++) {
			String hex = Integer.toHexString(0xFF & hash[i]);

			if (hex.length() == 1) {
				hexString.append('0');
			}
			hexString.append(hex);
		}

		return hexString.toString();
	}

	/**
	 * SHA256.
	 *
	 * @param message
	 * @return
	 * @throws Exception
	 * @throws NoSuchAlgorithmException
	 * @throws InvalidKeyException
	 */
	public static String getSHA256Encrypt(String message)
			throws Exception, NoSuchAlgorithmException, InvalidKeyException {
		StringBuffer hexString = new StringBuffer();

		MessageDigest md = MessageDigest.getInstance("SHA-256");

		byte[] hash = md.digest(message.getBytes("UTF-8"));

		for (int i = 0; i < hash.length; i++) {
			String hex = Integer.toHexString(0xFF & hash[i]);

			if (hex.length() == 1) {
				hexString.append('0');
			}
			hexString.append(hex);
		}

		return hexString.toString();
	}

	/**
	 * SHA1
	 *
	 * @param message
	 * @return
	 * @throws Exception
	 * @throws NoSuchAlgorithmException
	 * @throws InvalidKeyException
	 */
	public static byte[] getSHA1EncryptByte(String message)
			throws Exception, NoSuchAlgorithmException, InvalidKeyException {
		MessageDigest digest = MessageDigest.getInstance("SHA-1");
		digest.update(message.getBytes());
		return digest.digest();
	}

	/**
	 * HmacSHA256 값 비교 로직.
	 *
	 * @param message
	 * @param reqHashData
	 * @return
	 * @throws NoSuchAlgorithmException
	 * @throws InvalidKeyException
	 * @throws DecoderException
	 */
	public static boolean isHashCompare(String message, String reqHashData)
			throws NoSuchAlgorithmException, InvalidKeyException, DecoderException {
		String key = System.getProperty("hmac.key");
		boolean isHashCompare = true;

		byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
		SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "HmacSHA256");

		Mac mac = Mac.getInstance("HmacSHA256");
		mac.init(secretKeySpec);
		byte[] macBytes = mac.doFinal(message.getBytes());

		byte[] ba = new byte[reqHashData.length() / 2];
		for (int i = 0; i < ba.length; i++) {
			ba[i] = ((byte) Integer.parseInt(reqHashData.substring(2 * i, 2 * i + 2), 16));
		}

		if (!MessageDigest.isEqual(macBytes, ba)) {
			isHashCompare = false;
		}

		return isHashCompare;
	}

	public String toHexString(byte[] b) {
		StringBuffer sb = new StringBuffer();

		for (int i = 0; i < b.length; i++) {
			sb.append(String.format("%02X", b[i]));
		}

		return sb.toString();
	}

	public byte[] toHexString2(String test) {
		int len = test.length();
		byte[] data = new byte[len / 2];

		for (int i = 0; i < len; i += 2) {
			data[i / 2] = (byte) ((Character.digit(test.charAt(i), 16) << 4) + Character.digit(test.charAt(i + 1), 16));
		}

		return data;

	}

	// 128 크기 sha-512
	public static String getCustomSHA512(String key1, String key2){

		String result = null;
		if(key1 == null) {
			key1 = "";
		}

		if(key2 == null) {
			key2 = "";
		}

		try {
			MessageDigest md = MessageDigest.getInstance("SHA-512");
			md.reset();
			md.update(key1.getBytes("utf8"));
			md.update(key2.getBytes("utf8"));
			result = String.format("%0128x", new BigInteger(1, md.digest()));


		} catch (Exception e) {
			e.printStackTrace();
		}

		return result;

	}

	public static void main(String[] args) throws Exception {
		String userId = "jambler02";
		String userPwd = "1234qwer";
		String encPwd = "";

		encPwd = getCustomSHA512(userId, userPwd);
		System.out.println("[user Id Password]:[" + userId+" , "+userPwd + "]");
		System.out.println("[Encript Password]:[" + encPwd + "]");
		//System.out.println("[Password chk Result]:[" + checkPassword(userPwd, encPwd, userId) + "]");
	}

}
