package com.cameleer.server.app.security;

import com.cameleer.server.core.security.Ed25519SigningService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

import static org.junit.jupiter.api.Assertions.*;

/**
 * Unit tests for {@link Ed25519SigningServiceImpl}.
 * No Spring context needed — implementation constructed directly.
 */
class Ed25519SigningServiceTest {

    private Ed25519SigningService signingService;

    @BeforeEach
    void setUp() {
        signingService = Ed25519SigningServiceImpl.ephemeral();
    }

    @Test
    void getPublicKeyBase64_returnsNonNullBase64String() {
        String publicKeyBase64 = signingService.getPublicKeyBase64();
        assertNotNull(publicKeyBase64);
        assertFalse(publicKeyBase64.isBlank());
        // Verify it's valid Base64
        assertDoesNotThrow(() -> Base64.getDecoder().decode(publicKeyBase64));
    }

    @Test
    void sign_returnsBase64SignatureString() {
        String signature = signingService.sign("test payload");
        assertNotNull(signature);
        assertFalse(signature.isBlank());
        assertDoesNotThrow(() -> Base64.getDecoder().decode(signature));
    }

    @Test
    void sign_signatureVerifiesAgainstPublicKey() throws Exception {
        String payload = "important config data";
        String signatureBase64 = signingService.sign(payload);
        String publicKeyBase64 = signingService.getPublicKeyBase64();

        // Reconstruct public key from Base64
        byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyBase64);
        KeyFactory keyFactory = KeyFactory.getInstance("Ed25519");
        PublicKey publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyBytes));

        // Verify signature
        Signature verifier = Signature.getInstance("Ed25519");
        verifier.initVerify(publicKey);
        verifier.update(payload.getBytes(java.nio.charset.StandardCharsets.UTF_8));
        assertTrue(verifier.verify(Base64.getDecoder().decode(signatureBase64)),
                "Signature should verify against the public key");
    }

    @Test
    void sign_differentPayloadsProduceDifferentSignatures() {
        String sig1 = signingService.sign("payload one");
        String sig2 = signingService.sign("payload two");
        assertNotEquals(sig1, sig2, "Different payloads should produce different signatures");
    }

    @Test
    void sign_tamperedPayloadFailsVerification() throws Exception {
        String payload = "original payload";
        String signatureBase64 = signingService.sign(payload);
        String publicKeyBase64 = signingService.getPublicKeyBase64();

        byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyBase64);
        KeyFactory keyFactory = KeyFactory.getInstance("Ed25519");
        PublicKey publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyBytes));

        // Verify against tampered payload
        Signature verifier = Signature.getInstance("Ed25519");
        verifier.initVerify(publicKey);
        verifier.update("tampered payload".getBytes(java.nio.charset.StandardCharsets.UTF_8));
        assertFalse(verifier.verify(Base64.getDecoder().decode(signatureBase64)),
                "Tampered payload should fail verification");
    }
}
