package cloud.nstart.terravault.ordinis.outbox.webhook;

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

/**
 * HMAC-SHA256 signing для webhook deliveries. Receiver проверяет подпись через
 * shared secret чтобы убедиться что запрос от Ordinis.
 *
 * <p>Header format: {@code X-Ordinis-Signature: sha256=<hex>}.
 */
public final class HmacSigner {

  private static final String ALGORITHM = "HmacSHA256";
  public static final String HEADER_NAME = "X-Ordinis-Signature";

  private HmacSigner() {}

  /**
   * Подписать body shared secret'ом. Возвращает значение для header
   * (с префиксом {@code sha256=}).
   *
   * @param secret hex-encoded HMAC secret (64 chars = 32 bytes)
   * @param body raw bytes тела запроса
   * @return {@code sha256=<hex>}
   */
  public static String sign(String secret, byte[] body) {
    if (secret == null || secret.isBlank()) {
      throw new IllegalArgumentException("secret must not be empty");
    }
    try {
      Mac mac = Mac.getInstance(ALGORITHM);
      byte[] keyBytes = secret.getBytes(StandardCharsets.UTF_8);
      mac.init(new SecretKeySpec(keyBytes, ALGORITHM));
      byte[] hash = mac.doFinal(body);
      return "sha256=" + toHex(hash);
    } catch (NoSuchAlgorithmException e) {
      // HmacSHA256 — required JDK algorithm, не должен fail
      throw new IllegalStateException("HmacSHA256 unavailable", e);
    } catch (java.security.InvalidKeyException e) {
      throw new IllegalArgumentException("invalid HMAC key", e);
    }
  }

  private static String toHex(byte[] bytes) {
    StringBuilder sb = new StringBuilder(bytes.length * 2);
    for (byte b : bytes) {
      sb.append(String.format("%02x", b));
    }
    return sb.toString();
  }
}
