package com.zioinfo.mall.common;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * 결제·회원 민감정보 암호화 유틸 — AES-256-GCM.
 *
 * <p>GUARDiA 보안 불변 규칙: 카드번호·계좌번호 등 결제 민감정보는 평문 저장 금지.
 * {@code *_enc} 컬럼에 본 유틸로 암호화하여 저장하고, API 응답에는 절대 노출하지 않는다(마스킹만 노출).
 *
 * <p>저장 포맷: Base64( IV(12B) || ciphertext || GCM tag(16B) ).
 */
@Component
public class CryptoUtil {

    private static final int IV_LEN = 12;
    private static final int TAG_BITS = 128;
    private final SecretKeySpec key;
    private final SecureRandom random = new SecureRandom();

    public CryptoUtil(@Value("${guardia.crypto.secret:guardia-mall-aes-256-gcm-master-key-2026-zioinfo}") String secret) {
        try {
            byte[] digest = MessageDigest.getInstance("SHA-256").digest(secret.getBytes(StandardCharsets.UTF_8));
            this.key = new SecretKeySpec(digest, "AES");
        } catch (Exception e) {
            throw new IllegalStateException("암호화 키 초기화 실패", e);
        }
    }

    /** 평문을 AES-256-GCM으로 암호화하여 Base64 문자열로 반환. null/빈 입력은 그대로 반환. */
    public String encrypt(String plain) {
        if (plain == null || plain.isEmpty()) {
            return plain;
        }
        try {
            byte[] iv = new byte[IV_LEN];
            random.nextBytes(iv);
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(TAG_BITS, iv));
            byte[] ct = cipher.doFinal(plain.getBytes(StandardCharsets.UTF_8));
            byte[] out = new byte[iv.length + ct.length];
            System.arraycopy(iv, 0, out, 0, iv.length);
            System.arraycopy(ct, 0, out, iv.length, ct.length);
            return Base64.getEncoder().encodeToString(out);
        } catch (Exception e) {
            throw new RuntimeException("ERR-MALL-CRYPTO-01: 암호화 실패");
        }
    }

    /** Base64 암호문을 복호화. 복호화 실패 시 빈 문자열. */
    public String decrypt(String enc) {
        if (enc == null || enc.isEmpty()) {
            return enc;
        }
        try {
            byte[] all = Base64.getDecoder().decode(enc);
            byte[] iv = new byte[IV_LEN];
            System.arraycopy(all, 0, iv, 0, IV_LEN);
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            cipher.init(Cipher.DECRYPT_MODE, key, new GCMParameterSpec(TAG_BITS, iv));
            byte[] pt = cipher.doFinal(all, IV_LEN, all.length - IV_LEN);
            return new String(pt, StandardCharsets.UTF_8);
        } catch (Exception e) {
            return "";
        }
    }

    /** 카드/계좌번호 마스킹 — 마지막 4자리만 노출. */
    public static String maskTail(String value) {
        if (value == null || value.length() <= 4) {
            return "****";
        }
        String tail = value.substring(value.length() - 4);
        return "****-****-" + tail;
    }
}
