package com.sino.mci.inbound.webhook;

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

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
 * 入站 webhook 签名服务。
 *
 * <p>使用 HMAC-SHA256 / HMAC-SHA512 对原始 payload 进行签名，
 * 输出 Base64 编码签名、算法标识及时间戳，供业务系统验签使用。</p>
 */
@Slf4j
@Service
public class WebhookSignatureService {

    private static final String DEFAULT_ALGORITHM = "hmac-sha256";
    private static final String HMAC_SHA256 = "HmacSHA256";
    private static final String HMAC_SHA512 = "HmacSHA512";

    /**
     * 对原始 payload 进行签名。
     *
     * @param tenantCode 租户编码（用于日志/追踪，不参与签名计算）
     * @param payload    待签名的原始 payload 字符串
     * @param secret     租户 webhook 密钥
     * @param algorithm  签名算法，支持 hmac-sha256（默认）和 hmac-sha512
     * @return 签名结果，包含签名值、算法及时间戳
     */
    public WebhookSignature sign(String tenantCode, String payload, String secret, String algorithm) {
        String normalizedAlgorithm = normalizeAlgorithm(algorithm);
        String signature = hmacSign(tenantCode, payload, secret, normalizedAlgorithm);
        long timestamp = System.currentTimeMillis() / 1000;
        return new WebhookSignature(signature, normalizedAlgorithm, timestamp);
    }

    private String normalizeAlgorithm(String algorithm) {
        if (algorithm == null || algorithm.isBlank()) {
            return DEFAULT_ALGORITHM;
        }
        return switch (algorithm.toLowerCase().replace("_", "-")) {
            case "hmac-sha256", "sha256" -> "hmac-sha256";
            case "hmac-sha512", "sha512" -> "hmac-sha512";
            default -> DEFAULT_ALGORITHM;
        };
    }

    private String hmacSign(String tenantCode, String payload, String secret, String algorithm) {
        String hmacAlgorithm = algorithm.equals("hmac-sha512") ? HMAC_SHA512 : HMAC_SHA256;
        try {
            Mac mac = Mac.getInstance(hmacAlgorithm);
            SecretKeySpec keySpec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), hmacAlgorithm);
            mac.init(keySpec);
            byte[] signatureBytes = mac.doFinal(payload.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(signatureBytes);
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            log.error("Failed to sign webhook payload for tenant {}", tenantCode, e);
            throw new IllegalStateException("Webhook signature failed: " + algorithm, e);
        }
    }
}
