package com.sino.mci.inbound.webhook;

import org.junit.jupiter.api.Test;

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

import static org.assertj.core.api.Assertions.assertThat;

class WebhookSignatureServiceTest {

    private final WebhookSignatureService signatureService = new WebhookSignatureService();

    @Test
    void shouldSignPayloadWithHmacSha256() throws Exception {
        String payload = "{\"event_id\":\"evt_001\",\"tenant_code\":\"rescue\"}";
        String secret = "tenant-secret";

        WebhookSignature signature = signatureService.sign("rescue", payload, secret, "hmac-sha256");

        String expected = manualHmac(payload, secret, "HmacSHA256");
        assertThat(signature.signature()).isEqualTo(expected);
        assertThat(signature.algorithm()).isEqualTo("hmac-sha256");
        assertThat(signature.timestamp()).isGreaterThan(0);
    }

    @Test
    void shouldSignPayloadWithHmacSha512() throws Exception {
        String payload = "{\"event_id\":\"evt_001\"}";
        String secret = "tenant-secret";

        WebhookSignature signature = signatureService.sign("rescue", payload, secret, "hmac-sha512");

        String expected = manualHmac(payload, secret, "HmacSHA512");
        assertThat(signature.signature()).isEqualTo(expected);
        assertThat(signature.algorithm()).isEqualTo("hmac-sha512");
    }

    @Test
    void shouldDefaultToHmacSha256WhenAlgorithmIsBlank() {
        String payload = "{\"event_id\":\"evt_001\"}";
        String secret = "tenant-secret";

        WebhookSignature signature = signatureService.sign("rescue", payload, secret, null);

        assertThat(signature.algorithm()).isEqualTo("hmac-sha256");
    }

    @Test
    void shouldProduceDifferentSignaturesForDifferentSecrets() {
        String payload = "{\"event_id\":\"evt_001\"}";

        WebhookSignature first = signatureService.sign("rescue", payload, "secret-a", "hmac-sha256");
        WebhookSignature second = signatureService.sign("rescue", payload, "secret-b", "hmac-sha256");

        assertThat(first.signature()).isNotEqualTo(second.signature());
    }

    @Test
    void shouldProduceDifferentSignaturesForDifferentAlgorithms() {
        String payload = "{\"event_id\":\"evt_001\"}";
        String secret = "tenant-secret";

        WebhookSignature sha256 = signatureService.sign("rescue", payload, secret, "hmac-sha256");
        WebhookSignature sha512 = signatureService.sign("rescue", payload, secret, "hmac-sha512");

        assertThat(sha256.signature()).isNotEqualTo(sha512.signature());
    }

    private String manualHmac(String payload, String secret, String algorithm) throws Exception {
        Mac mac = Mac.getInstance(algorithm);
        SecretKeySpec keySpec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), algorithm);
        mac.init(keySpec);
        byte[] signatureBytes = mac.doFinal(payload.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(signatureBytes);
    }
}
