package cn.novalon.manage.gateway.service.impl;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.test.util.ReflectionTestUtils;

import javax.crypto.SecretKey;

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

@ExtendWith(MockitoExtension.class)
class JwtKeyServiceImplTest {

    @InjectMocks
    private JwtKeyServiceImpl jwtKeyService;

    @BeforeEach
    void setUp() {
        ReflectionTestUtils.setField(jwtKeyService, "configuredSecret", null);
        ReflectionTestUtils.setField(jwtKeyService, "encryptionPassword", "testEncryptionPassword");
        ReflectionTestUtils.setField(jwtKeyService, "rotationEnabled", true);
    }

    @Test
    void testInitializeKeys_GeneratesNewKey() {
        jwtKeyService.initializeKeys();

        String version = jwtKeyService.getCurrentKeyVersion();
        SecretKey key = jwtKeyService.getCurrentSigningKey();

        assertNotNull(version);
        assertNotNull(key);
        assertEquals("v1", version);
        assertEquals("AES", key.getAlgorithm());
    }

    @Test
    void testGenerateSecureKey_GeneratesValidKey() {
        String key = jwtKeyService.generateSecureKey();

        assertNotNull(key);
        assertFalse(key.isEmpty());
        assertTrue(jwtKeyService.validateKeyStrength(key));
    }

    @Test
    void testValidateKeyStrength_ValidKey() {
        String validKey = "StrongPassword123ABC!@#XYZabcdefg";
        assertTrue(jwtKeyService.validateKeyStrength(validKey));
    }

    @Test
    void testValidateKeyStrength_WeakKey() {
        String weakKey = "weak";
        assertFalse(jwtKeyService.validateKeyStrength(weakKey));
    }

    @Test
    void testValidateKeyStrength_NullKey() {
        assertFalse(jwtKeyService.validateKeyStrength(null));
    }

    @Test
    void testValidateKeyStrength_ShortKey() {
        String shortKey = "Short1!";
        assertFalse(jwtKeyService.validateKeyStrength(shortKey));
    }

    @Test
    void testEncryptKey_WithPassword() {
        String originalKey = "MySecretKey123!";
        String encryptedKey = jwtKeyService.encryptKey(originalKey);

        assertNotNull(encryptedKey);
        assertNotEquals(originalKey, encryptedKey);
        assertTrue(encryptedKey.length() > originalKey.length());
    }

    @Test
    void testEncryptDecryptKey_RoundTrip() {
        String originalKey = "MySecretKey123!";
        String encryptedKey = jwtKeyService.encryptKey(originalKey);
        String decryptedKey = jwtKeyService.decryptKey(encryptedKey);

        assertNotNull(encryptedKey);
        assertNotNull(decryptedKey);
        assertEquals(originalKey, decryptedKey);
    }

    @Test
    void testRotateKey_CreatesNewVersion() {
        jwtKeyService.initializeKeys();
        String oldVersion = jwtKeyService.getCurrentKeyVersion();

        jwtKeyService.rotateKey();

        String newVersion = jwtKeyService.getCurrentKeyVersion();
        SecretKey newKey = jwtKeyService.getCurrentSigningKey();

        assertNotEquals(oldVersion, newVersion);
        assertEquals("v2", newVersion);
        assertNotNull(newKey);
        assertEquals("AES", newKey.getAlgorithm());
    }

    @Test
    void testGetSigningKeyByVersion_ReturnsCorrectKey() {
        jwtKeyService.initializeKeys();
        SecretKey v1Key = jwtKeyService.getSigningKeyByVersion("v1");

        assertNotNull(v1Key);
        assertEquals("AES", v1Key.getAlgorithm());
    }

    @Test
    void testGetSigningKeyByVersion_InvalidVersion() {
        jwtKeyService.initializeKeys();
        SecretKey invalidKey = jwtKeyService.getSigningKeyByVersion("v999");

        assertNull(invalidKey);
    }

    @Test
    void testRotateKey_Disabled() {
        ReflectionTestUtils.setField(jwtKeyService, "rotationEnabled", false);
        jwtKeyService.initializeKeys();
        String oldVersion = jwtKeyService.getCurrentKeyVersion();

        jwtKeyService.rotateKey();

        String newVersion = jwtKeyService.getCurrentKeyVersion();
        assertEquals(oldVersion, newVersion);
    }

    @Test
    void testShouldRotateKey_NewKey() {
        jwtKeyService.initializeKeys();
        
        String currentVersion = jwtKeyService.getCurrentKeyVersion();
        SecretKey currentKey = jwtKeyService.getCurrentSigningKey();
        
        assertNotNull(currentVersion, "Current version should not be null");
        assertNotNull(currentKey, "Current signing key should not be null");
    }

    @Test
    void testMultipleRotations_CreatesMultipleVersions() {
        jwtKeyService.initializeKeys();

        jwtKeyService.rotateKey();
        assertEquals("v2", jwtKeyService.getCurrentKeyVersion());

        jwtKeyService.rotateKey();
        assertEquals("v3", jwtKeyService.getCurrentKeyVersion());

        jwtKeyService.rotateKey();
        assertEquals("v4", jwtKeyService.getCurrentKeyVersion());

        assertNotNull(jwtKeyService.getSigningKeyByVersion("v1"));
        assertNotNull(jwtKeyService.getSigningKeyByVersion("v2"));
        assertNotNull(jwtKeyService.getSigningKeyByVersion("v3"));
        assertNotNull(jwtKeyService.getSigningKeyByVersion("v4"));
    }

    @Test
    void testEncryptKey_WithoutPassword() {
        ReflectionTestUtils.setField(jwtKeyService, "encryptionPassword", "");
        String originalKey = "MySecretKey123!";
        String encryptedKey = jwtKeyService.encryptKey(originalKey);

        assertEquals(originalKey, encryptedKey);
    }

    @Test
    void testDecryptKey_WithoutPassword() {
        ReflectionTestUtils.setField(jwtKeyService, "encryptionPassword", "");
        String originalKey = "MySecretKey123!";
        String decryptedKey = jwtKeyService.decryptKey(originalKey);

        assertEquals(originalKey, decryptedKey);
    }
}