package com.ruoyi.web.modules.openstats.support;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.UUID;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;
import com.ruoyi.web.modules.openstats.constant.OpenStatsConstants;

@ExtendWith(MockitoExtension.class)
class OpenStatsTokenCryptoSupportTest
{
    @InjectMocks
    private OpenStatsTokenCryptoSupport cryptoSupport;

    @Test
    void validateEncryptedToken_validUuidCipherText()
    {
        String uuid = UUID.randomUUID().toString();
        String encrypted = encrypt(uuid);

        assertTrue(cryptoSupport.validateEncryptedToken(encrypted));
        assertEquals(uuid, cryptoSupport.decrypt(encrypted));
    }

    @Test
    void validateEncryptedToken_plainUuidRejected()
    {
        assertFalse(cryptoSupport.validateEncryptedToken(UUID.randomUUID().toString()));
    }

    @Test
    void validateEncryptedToken_nonUuidPlainAfterDecryptRejected()
    {
        assertFalse(cryptoSupport.validateEncryptedToken(encrypt("not-a-uuid")));
    }

    @Test
    void validateEncryptedToken_badBase64Rejected()
    {
        assertFalse(cryptoSupport.validateEncryptedToken("%%%invalid-base64%%%"));
    }

    @Test
    void isUuid_standardFormat()
    {
        assertTrue(cryptoSupport.isUuid("550e8400-e29b-41d4-a716-446655440000"));
        assertFalse(cryptoSupport.isUuid("550e8400e29b41d4a716446655440000"));
        assertFalse(cryptoSupport.isUuid(null));
    }

    private String encrypt(String plain)
    {
        try
        {
            Cipher cipher = Cipher.getInstance(OpenStatsConstants.AES_TRANSFORMATION);
            SecretKeySpec keySpec = new SecretKeySpec(
                    OpenStatsConstants.AES_KEY.getBytes(StandardCharsets.UTF_8), "AES");
            IvParameterSpec ivSpec = new IvParameterSpec(
                    OpenStatsConstants.AES_IV.getBytes(StandardCharsets.UTF_8));
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
            byte[] cipherBytes = cipher.doFinal(plain.getBytes(StandardCharsets.UTF_8));
            String encoded = Base64.getEncoder().encodeToString(cipherBytes);
            assertNotNull(encoded);
            return encoded;
        }
        catch (Exception ex)
        {
            throw new IllegalStateException(ex);
        }
    }
}
