package com.zioinfo.signage.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

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

/**
 * AES-256-GCM 자격증명 암호화 유틸리티.
 * 보안 불변 규칙: 서버 자격증명은 암호화 DB에만 저장, API 응답에 절대 노출 금지.
 */
@Slf4j
@Component
public class CryptoUtil {

    private static final String ALGO = "AES/GCM/NoPadding";
    private static final int GCM_IV_LEN = 12;
    private static final int GCM_TAG_LEN = 128;
    // 운영 시 환경변수로 주입 권장
    private static final String KEY_HEX = "7a696f696e666f7369676e6167656b6579323032367365637265746b65797878";

    private SecretKey secretKey() {
        byte[] key = new byte[32];
        byte[] src = KEY_HEX.getBytes(StandardCharsets.UTF_8);
        System.arraycopy(src, 0, key, 0, Math.min(src.length, 32));
        return new SecretKeySpec(key, "AES");
    }

    public String encrypt(String plain) {
        if (plain == null) return null;
        try {
            byte[] iv = new byte[GCM_IV_LEN];
            new SecureRandom().nextBytes(iv);
            Cipher cipher = Cipher.getInstance(ALGO);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey(), new GCMParameterSpec(GCM_TAG_LEN, iv));
            byte[] enc = cipher.doFinal(plain.getBytes(StandardCharsets.UTF_8));
            byte[] result = new byte[iv.length + enc.length];
            System.arraycopy(iv, 0, result, 0, iv.length);
            System.arraycopy(enc, 0, result, iv.length, enc.length);
            return Base64.getEncoder().encodeToString(result);
        } catch (Exception e) {
            log.error("암호화 실패", e);
            throw new RuntimeException("CRYPTO_ERR", e);
        }
    }

    public String decrypt(String encrypted) {
        if (encrypted == null) return null;
        try {
            byte[] raw = Base64.getDecoder().decode(encrypted);
            byte[] iv = new byte[GCM_IV_LEN];
            System.arraycopy(raw, 0, iv, 0, GCM_IV_LEN);
            Cipher cipher = Cipher.getInstance(ALGO);
            cipher.init(Cipher.DECRYPT_MODE, secretKey(), new GCMParameterSpec(GCM_TAG_LEN, iv));
            byte[] dec = cipher.doFinal(raw, GCM_IV_LEN, raw.length - GCM_IV_LEN);
            return new String(dec, StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("복호화 실패", e);
            throw new RuntimeException("CRYPTO_ERR", e);
        }
    }
}
