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

import java.util.Arrays;
import java.util.Map;

import javax.crypto.SecretKey;

import com.eactive.eai.common.hsm.HsmCryptoService;
import com.eactive.eai.common.security.keyderiv.DerivedKey;
import com.eactive.eai.common.security.keyderiv.KeyDerivationStrategy;
import com.eactive.eai.common.util.ApplicationContextProvider;

/**
 * HSM 마스터키 + 런타임 컨텍스트값 XOR 조합으로 키를 도출하는 전략.
 *
 * key_deriv_params (JSON) 예시:
 * {
 *   "hsmKeyAlias"   : "MASTER_KEY_AES",
 *   "contextKey"    : "X-Api-Enc-Key",   -- runtimeContext에서 꺼낼 키 이름
 *   "offset"        : "0",               -- contextKey 값 중 사용할 시작 위치 (byte)
 *   "length"        : "16"               -- contextKey 값 중 사용할 길이 (byte)
 * }
 */
public class HsmContextXorKeyDerivationStrategy implements KeyDerivationStrategy {

	/** DB key_deriv_strategy 컬럼에 사용하는 FQCN 참조용 상수. */
	public static final String STRATEGY_CLASS = HsmContextXorKeyDerivationStrategy.class.getName();

	private static final String PARAM_OFFSET        = "offset";
	private static final String PARAM_LENGTH        = "length";

	@Override
	public DerivedKey deriveKey(Map<String, String> params, Map<String, String> runtimeContext) throws Exception {
		String hsmKeyAlias = required(params, PARAM_HSM_KEY_ALIAS);
		String contextKey  = required(params, PARAM_CONTEXT_KEY);
		int offset         = Integer.parseInt(params.getOrDefault(PARAM_OFFSET, "0"));
		int length         = Integer.parseInt(required(params, PARAM_LENGTH));

		SecretKey masterKey = hsmCryptoService().getSecretKey(hsmKeyAlias);
		byte[] masterBytes  = masterKey.getEncoded();

		String contextValue = runtimeContext.getOrDefault(contextKey, "");
		byte[] contextBytes = contextValue.getBytes("UTF-8");

		byte[] derived = xor(masterBytes, contextBytes, offset, length);
		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 byte[] xor(byte[] masterBytes, byte[] contextBytes, int offset, int length) {
		byte[] derived = Arrays.copyOf(masterBytes, masterBytes.length);
		for (int i = 0; i < length && i < derived.length; i++) {
			int contextIdx = offset + i;
			if (contextIdx < contextBytes.length) {
				derived[i] ^= contextBytes[contextIdx];
			}
		}
		return derived;
	}

	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;
	}

	private HsmCryptoService hsmCryptoService() {
		return ApplicationContextProvider.getContext().getBean(HsmCryptoService.class);
	}
}
