package com.eactive.eai.custom.common.security.keyderiv;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;

import com.eactive.eai.common.security.keyderiv.DerivedKey;
import com.eactive.eai.common.security.keyderiv.strategy.BaseHsmKeyDerivationStrategy;

/**
 * HSM 마스터키 + 런타임 컨텍스트값을 연결(concatenate)한 뒤 SHA-256 해싱으로 키를 도출하는 전략.
 * SHA-256 출력은 항상 32바이트(AES-256)이므로 별도 keyLength 파라미터가 불필요하다.
 *
 * key_deriv_params (JSON) 예시:
 * {
 *   "hsmKeyAlias" : "MASTER_KEY_AES",
 *   "contextKey"  : "X-Api-Group-Seq"  -- runtimeContext에서 꺼낼 키 이름
 * }
 */
public class HsmContextSha256KeyDerivationStrategy extends BaseHsmKeyDerivationStrategy {

	@Override
	public DerivedKey deriveKey(Map<String, String> params, Map<String, String> runtimeContext) throws Exception {
		byte[] masterKeyBytes = super.getHsmKey(params);
		
		return deriveKey(params, runtimeContext, masterKeyBytes);
	}

	public DerivedKey deriveKey(Map<String, String> params, Map<String, String> runtimeContext, byte[] masterKeyBytes)
			throws NoSuchAlgorithmException {
		String contextKey  = required(params, PARAM_CONTEXT_KEY);
		byte[] contextBytes   = runtimeContext.getOrDefault(contextKey, "")
				.getBytes(StandardCharsets.UTF_8);

		byte[] combined = new byte[masterKeyBytes.length + contextBytes.length];
		System.arraycopy(masterKeyBytes, 0, combined, 0, masterKeyBytes.length);
		System.arraycopy(contextBytes,  0, combined, masterKeyBytes.length, contextBytes.length);

		byte[] derived = MessageDigest.getInstance("SHA-256").digest(combined);
		return new DerivedKey(derived, derived);
	}

	@Override
	public String buildCacheKey(String cryptoName, Map<String, String> params, Map<String, String> runtimeContext) {
		String contextKey   = params.getOrDefault(PARAM_CONTEXT_KEY, "");
		String contextValue = runtimeContext.getOrDefault(contextKey, "");
		return cryptoName + ":" + contextValue;
	}

	private String required(Map<String, String> params, String key) {
		String value = params.get(key);
		if (value == null || value.trim().isEmpty()) {
			throw new IllegalArgumentException("key_deriv_params 필수값 누락: " + key);
		}
		return value;
	}
}
