package com.eactive.eai.common.hsm;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;

import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.SecretKeySpec;

public class HsmAddKeyTest {

	/**
	 * JDK 버전에 따라 SunPKCS11 Provider 를 생성한다.
	 *
	 * JDK 8 : SunPKCS11(InputStream) 생성자를 리플렉션으로 호출 JDK 9+:
	 * Provider.configure(configFilePath) 를 리플렉션으로 호출
	 *
	 * 두 경로 모두 리플렉션을 사용하므로 컴파일 타임에 JDK 버전 의존성이 없다.
	 */
	static Provider createProvider(String cfgContent) throws Exception {
		String javaVersion = System.getProperty("java.version");
		if (javaVersion.startsWith("1.")) {
			// JDK 8: new SunPKCS11(InputStream)
			InputStream is = new ByteArrayInputStream(cfgContent.getBytes("UTF-8"));
			return (Provider) Class.forName("sun.security.pkcs11.SunPKCS11").getConstructor(InputStream.class)
					.newInstance(is);
		} else {
			// JDK 9+: Security.getProvider("SunPKCS11").configure(configFilePath)
			// configure() 는 JDK 9 에서 추가된 메서드이므로 리플렉션으로 호출
			File tmp = File.createTempFile("pkcs11-hsm-", ".cfg");
			tmp.deleteOnExit();
			Files.write(tmp.toPath(), cfgContent.getBytes("UTF-8"));
			Provider base = Security.getProvider("SunPKCS11");
			Method configure = Provider.class.getMethod("configure", String.class);
			return (Provider) configure.invoke(base, tmp.getAbsolutePath());
		}
	}

	public static void main(String[] args) throws Exception {
//    	String config = "name = ProtectServer\r\n"
//    			+ "library = /usr/safenet/protecttoolkit5/ptk/lib/libcryptoki.so\r\n"
//    			+ "slot = 0";

//		String config = "name = SoftHSM\r\nlibrary = C:/SoftHSM2/lib/softhsm2-x64.dll\r\nslotListIndex = 0\r\n";

		String config = "name = SoftHSM\r\n"
		        + "library = C:/SoftHSM2/lib/softhsm2-x64.dll\r\n"
		        + "slotListIndex = 0\r\n"
		        + "attributes(*, CKO_SECRET_KEY, CKK_AES) = {\r\n"
		        + "  CKA_TOKEN = true\r\n"
		        + "  CKA_SENSITIVE = false\r\n"
		        + "  CKA_EXTRACTABLE = true\r\n"
		        + "  CKA_ENCRYPT = true\r\n"
		        + "  CKA_DECRYPT = true\r\n"
		        + "}\r\n";
		
		KeyStore keyStore;
//        Provider pkcs11Provider = HsmManagerSingleTest.createProvider(config);
		InputStream is = new ByteArrayInputStream(config.getBytes("UTF-8"));
		Provider pkcs11Provider = (Provider) Class.forName("sun.security.pkcs11.SunPKCS11")
				.getConstructor(InputStream.class).newInstance(is);
		Security.addProvider(pkcs11Provider);
		String pin = "1234";
		keyStore = KeyStore.getInstance("PKCS11", pkcs11Provider);

		char[] pinChars = (pin != null) ? pin.toCharArray() : null;
		keyStore.load(null, pinChars);

//		addKey("20250916_openapi_erpbank_t", "55187afc5d36a2e3b71f3bf992947389964ac5ea0bc8ebe2297265134fa34cb9",
//				keyStore, pkcs11Provider);
//		addKey("20240401_openapi_kakaobank_t", "f009328cb94f5c866ff730735ce8031b43ca84f9266ced641b4046c6a5c21038",
//				keyStore, pkcs11Provider);
//		addKey("20250620_openapi_coocon_t", "3e7a7673392c424e58265c7b6f2e596f7a59542b277472704c3d5d6c70226673",
//				keyStore, pkcs11Provider);
//		addKey("20211221_openapi_kakaopay_t", "23667b665037785c3c312a414b6c566d2f3832476b254646727c4d703d484534",
//				keyStore, pkcs11Provider);
//
//		addKey("20250916_openapi_erpbank_t_0", "55187afc5d36a2e3b71f3bf992947389964ac5ea0bc8ebe2297265134fa34cb9",
//				keyStore, pkcs11Provider);
//		addKey("20240401_openapi_kakaobank_t_0", "f009328cb94f5c866ff730735ce8031b43ca84f9266ced641b4046c6a5c21038",
//				keyStore, pkcs11Provider);
//		addKey("20250620_openapi_coocon_t_0", "3e7a7673392c424e58265c7b6f2e596f7a59542b277472704c3d5d6c70226673",
//				keyStore, pkcs11Provider);
//		addKey("20211221_openapi_kakaopay_t_0", "23667b665037785c3c312a414b6c566d2f3832476b254646727c4d703d484534",
//				keyStore, pkcs11Provider);

		addKey("20260518_openapi_npayloan_t", "7f7f6608a0c2f28d9a7e53f81b265f12b46f893ffcecc253bdc0561338e10208",
				keyStore, pkcs11Provider);
		addKey("20260518_openapi_npayloan_iv_t", "b797008af20f0e1eda6c71d14bec5bb7",
				keyStore, pkcs11Provider);
		addKey("20241022_openapi_toss_t", "3051557a6c786475536c4f532f4c6b6b436a4c312f42434947764d336b66306e",
				keyStore, pkcs11Provider);
		addKey("20250307_openapi_tossbank_t", "48b8465313d6fc529a9f16c3347cde55a663efaf9ade41429c1cb484398bcf93",
				keyStore, pkcs11Provider);
		addKey("20250307_openapi_tossbank_iv_t", "2bdf93b1f872962d2aa2f890e179e3e0",
				keyStore, pkcs11Provider);
		addKey("20240524_openapi_banksalad_t", "466166733957513862616a646e55686a353759554c784e4a6463783279767035",
				keyStore, pkcs11Provider);
		
		System.out.println("HsmManager] 초기화 완료. Provider=" + pkcs11Provider.getName());

		java.util.Enumeration<String> aliases = keyStore.aliases();
		StringBuilder aliasList = new StringBuilder();
		while (aliases.hasMoreElements()) {
			if (aliasList.length() > 0)
				aliasList.append(", ");

			String alias = aliases.nextElement();
			aliasList.append(alias);

			java.security.Key key = keyStore.getKey(alias, null);
			if (key instanceof SecretKey) {
				SecretKey secretKey = (SecretKey) key;
				if (secretKey.getEncoded() != null) {
					String encBase64 = Base64.getEncoder().encodeToString(secretKey.getEncoded());
					System.out.println("HsmManager] HSM - alias:" + alias + ", base64:" + encBase64 + ", secretKey:" + secretKey);
				} else {
					System.out
							.println("HsmManager] HSM - secretKey null - alias:" + alias + ", secretKey:" + secretKey);
				}
			}
		}
		System.out.println("HsmManager] HSM 키 목록: [" + aliasList + "]");
	}

	private static void addKey(String keyAlias, String keyValue, KeyStore keyStore, Provider pkcs11Provider)
			throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException, InvalidKeySpecException {
		byte[] keyBytes = hexToBytes(keyValue);
		
		SecretKeySpec spec = new SecretKeySpec(keyBytes, "AES");
		SecretKeyFactory factory = SecretKeyFactory.getInstance("AES", pkcs11Provider);
		SecretKey fixedKey = (SecretKey) factory.generateSecret(spec);
		
//		SecretKey fixedKey = new SecretKeySpec(keyBytes, "AES");
		
		keyStore.setKeyEntry(keyAlias, fixedKey, null, null);

//		// 2. wrapping key 생성 (최초 1회만 — 이후엔 재사용)
//		KeyGenerator wrapKeyGen = KeyGenerator.getInstance("AES", pkcs11Provider);
//		wrapKeyGen.init(256);
//		SecretKey wrappingKey = wrapKeyGen.generateKey();
//
//		// 3. 테스트 환경 key 값 지정
//		byte[] testKeyBytes = hexToBytes(keyValue);
//		SecretKey targetKeySpec = new SecretKeySpec(testKeyBytes, "AES");
//
//		// 4. wrap
//		Cipher wrapCipher = Cipher.getInstance("AESWRAP", pkcs11Provider);
//		wrapCipher.init(Cipher.WRAP_MODE, wrappingKey);
//		byte[] wrapped = wrapCipher.wrap(targetKeySpec);
//
//		// 5. unwrap → SoftHSM2 내부에 실제 등록
//		Cipher unwrapCipher = Cipher.getInstance("AESWRAP", pkcs11Provider);
//		unwrapCipher.init(Cipher.UNWRAP_MODE, wrappingKey);
//		SecretKey hsmKey = (SecretKey) unwrapCipher.unwrap(wrapped, "AES", Cipher.SECRET_KEY
//
//		);
//
//		// 6. 평문 byte 배열 즉시 제거
//		Arrays.fill(testKeyBytes, (byte) 0);
//
//		System.out.println("Key 등록 완료: " + hsmKey.getAlgorithm() + " / " + hsmKey.getFormat());
//
//		// 7. 등록 확인 — alias 지정해서 KeyStore에 올리고 싶으면:
//		keyStore.setKeyEntry(keyAlias, hsmKey, null, null);
	}

	private static byte[] hexToBytes(String hex) {
		int len = hex.length();
		byte[] data = new byte[len / 2];
		for (int i = 0; i < len; i += 2) {
			data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16));
		}
		return data;
	}

	public static String bytesToHex(byte[] bytes) {
		StringBuilder sb = new StringBuilder();
		for (byte b : bytes) {
			sb.append(String.format("%02X", b));
		}
		return sb.toString();
	}

}
