package dev.lions.user.manager.client.view;

import io.quarkus.oidc.IdToken;
import io.quarkus.oidc.OidcSession;
import io.quarkus.security.identity.SecurityIdentity;
import org.eclipse.microprofile.jwt.JsonWebToken;
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.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;

import java.util.Set;

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

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class UserSessionBeanTest {

    @Mock
    SecurityIdentity securityIdentity;

    @Mock
    @IdToken
    JsonWebToken idToken;

    @Mock
    OidcSession oidcSession;

    @InjectMocks
    UserSessionBean userSessionBean;

    @BeforeEach
    void setUp() {
        // Configuration par défaut pour les tests
    }

    @Test
    void testLoadUserInfoWithToken() {
        when(securityIdentity.isAnonymous()).thenReturn(false);
        when(idToken.getClaim("preferred_username")).thenReturn("testuser");
        when(idToken.getClaim("email")).thenReturn("test@example.com");
        when(idToken.getClaim("given_name")).thenReturn("John");
        when(idToken.getClaim("family_name")).thenReturn("Doe");
        when(idToken.getClaim("name")).thenReturn("John Doe");

        userSessionBean.loadUserInfo();

        assertEquals("testuser", userSessionBean.getUsername());
        assertEquals("test@example.com", userSessionBean.getEmail());
        assertEquals("John", userSessionBean.getFirstName());
        assertEquals("Doe", userSessionBean.getLastName());
        assertEquals("John Doe", userSessionBean.getFullName());
        assertEquals("JD", userSessionBean.getInitials());
    }

    @Test
    void testLoadUserInfoAnonymous() {
        when(securityIdentity.isAnonymous()).thenReturn(true);

        userSessionBean.loadUserInfo();

        assertEquals("Utilisateur", userSessionBean.getUsername());
        assertEquals("utilisateur@lions.dev", userSessionBean.getEmail());
        assertEquals("Utilisateur", userSessionBean.getFullName());
        assertEquals("U", userSessionBean.getInitials());
    }

    @Test
    void testLoadUserInfoNullToken() {
        when(securityIdentity.isAnonymous()).thenReturn(true);
        // idToken is null by default when securityIdentity.isAnonymous() is true

        userSessionBean.loadUserInfo();

        assertEquals("Utilisateur", userSessionBean.getUsername());
    }

    @Test
    void testGenerateInitials() {
        // Test avec nom complet
        when(securityIdentity.isAnonymous()).thenReturn(false);
        when(idToken.getClaim("name")).thenReturn("John Doe");
        when(idToken.getClaim("preferred_username")).thenReturn("testuser");
        when(idToken.getClaim("email")).thenReturn("test@example.com");
        when(idToken.getClaim("given_name")).thenReturn("John");
        when(idToken.getClaim("family_name")).thenReturn("Doe");

        userSessionBean.loadUserInfo();

        assertEquals("JD", userSessionBean.getInitials());
    }

    @Test
    void testGenerateInitialsSingleName() {
        when(securityIdentity.isAnonymous()).thenReturn(false);
        when(idToken.getClaim("name")).thenReturn("John");
        when(idToken.getClaim("preferred_username")).thenReturn("testuser");
        when(idToken.getClaim("email")).thenReturn("test@example.com");
        when(idToken.getClaim("given_name")).thenReturn("John");
        when(idToken.getClaim("family_name")).thenReturn(null);

        userSessionBean.loadUserInfo();

        assertEquals("JO", userSessionBean.getInitials());
    }

    @Test
    void testGetPrimaryRole() {
        when(securityIdentity.isAnonymous()).thenReturn(false);
        when(securityIdentity.getRoles()).thenReturn(Set.of("admin", "user_manager"));
        // Load user info first to initialize the bean
        userSessionBean.loadUserInfo();

        String primaryRole = userSessionBean.getPrimaryRole();

        assertEquals("Administrateur", primaryRole);
    }

    @Test
    void testGetPrimaryRoleUserManager() {
        when(securityIdentity.isAnonymous()).thenReturn(false);
        when(securityIdentity.getRoles()).thenReturn(Set.of("user_manager"));
        // Load user info first to initialize the bean
        userSessionBean.loadUserInfo();

        String primaryRole = userSessionBean.getPrimaryRole();

        assertEquals("Gestionnaire", primaryRole);
    }

    @Test
    void testGetPrimaryRoleUserViewer() {
        when(securityIdentity.isAnonymous()).thenReturn(false);
        when(securityIdentity.getRoles()).thenReturn(Set.of("user_viewer"));
        // Load user info first to initialize the bean
        userSessionBean.loadUserInfo();

        String primaryRole = userSessionBean.getPrimaryRole();

        assertEquals("Consultant", primaryRole);
    }

    @Test
    void testGetRoles() {
        when(securityIdentity.isAnonymous()).thenReturn(false);
        when(securityIdentity.getRoles()).thenReturn(Set.of("admin", "user_manager"));
        // Load user info first to initialize the bean
        userSessionBean.loadUserInfo();

        Set<String> roles = userSessionBean.getRoles();

        assertFalse(roles.isEmpty());
        assertTrue(roles.contains("admin"));
        assertTrue(roles.contains("user_manager"));
    }

    @Test
    void testGetRolesAnonymous() {
        when(securityIdentity.isAnonymous()).thenReturn(true);
        // Load user info first to initialize the bean
        userSessionBean.loadUserInfo();

        Set<String> roles = userSessionBean.getRoles();

        assertFalse(roles.isEmpty());
        assertTrue(roles.contains("Utilisateur"));
    }

    @Test
    void testIsAuthenticated() {
        when(securityIdentity.isAnonymous()).thenReturn(false);

        assertTrue(userSessionBean.isAuthenticated());
    }

    @Test
    void testIsAuthenticatedAnonymous() {
        when(securityIdentity.isAnonymous()).thenReturn(true);

        assertFalse(userSessionBean.isAuthenticated());
    }

    @Test
    void testHasRole() {
        when(securityIdentity.isAnonymous()).thenReturn(false);
        when(securityIdentity.getRoles()).thenReturn(Set.of("admin", "user_manager"));
        // Load user info first to initialize the bean
        userSessionBean.loadUserInfo();

        assertTrue(userSessionBean.hasRole("admin"));
        assertTrue(userSessionBean.hasRole("user_manager"));
        assertFalse(userSessionBean.hasRole("auditor"));
    }

    @Test
    void testHasRoleAnonymous() {
        when(securityIdentity.isAnonymous()).thenReturn(true);
        // Load user info first to initialize the bean
        userSessionBean.loadUserInfo();

        assertFalse(userSessionBean.hasRole("admin"));
    }

    @Test
    void testGetIssuer() {
        when(idToken.getIssuer()).thenReturn("https://security.lions.dev/realms/master");

        String issuer = userSessionBean.getIssuer();

        assertEquals("https://security.lions.dev/realms/master", issuer);
    }

    @Test
    void testGetIssuerNull() {
        // Mock idToken.getIssuer() to throw an exception to simulate null token
        when(idToken.getIssuer()).thenThrow(new RuntimeException("Token is null"));

        String issuer = userSessionBean.getIssuer();

        assertEquals("Non disponible", issuer);
    }

    @Test
    void testGetSubject() {
        when(idToken.getSubject()).thenReturn("user-123");

        String subject = userSessionBean.getSubject();

        assertEquals("user-123", subject);
    }

    @Test
    void testGetSessionId() {
        when(idToken.getClaim("sid")).thenReturn("session-123");

        String sessionId = userSessionBean.getSessionId();

        assertEquals("session-123", sessionId);
    }

    @Test
    void testGetExpirationTime() {
        when(idToken.getExpirationTime()).thenReturn(1735689600L); // 2025-01-01 00:00:00 UTC

        java.util.Date expiration = userSessionBean.getExpirationTime();

        assertNotNull(expiration);
    }

    @Test
    void testGetIssuedAt() {
        when(idToken.getIssuedAtTime()).thenReturn(1735603200L); // 2024-12-31 00:00:00 UTC

        java.util.Date issuedAt = userSessionBean.getIssuedAt();

        assertNotNull(issuedAt);
    }

    @Test
    void testGetAudience() {
        when(idToken.getAudience()).thenReturn(Set.of("client1", "client2"));

        String audience = userSessionBean.getAudience();

        assertTrue(audience.contains("client1"));
        assertTrue(audience.contains("client2"));
    }

    @Test
    void testGetAuthorizedParty() {
        when(idToken.getClaim("azp")).thenReturn("lions-user-manager-client");

        String azp = userSessionBean.getAuthorizedParty();

        assertEquals("lions-user-manager-client", azp);
    }

    @Test
    void testIsEmailVerified() {
        when(idToken.getClaim("email_verified")).thenReturn(true);

        assertTrue(userSessionBean.isEmailVerified());
    }

    @Test
    void testIsEmailVerifiedFalse() {
        when(idToken.getClaim("email_verified")).thenReturn(false);

        assertFalse(userSessionBean.isEmailVerified());
    }
}

