package dev.lions.user.manager.dto.role;

import dev.lions.user.manager.enums.role.TypeRole;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

class RoleDTOTest {

    @Test
    void testIsRealmRole_true() {
        RoleDTO role = new RoleDTO();
        role.setTypeRole(TypeRole.REALM_ROLE);
        assertTrue(role.isRealmRole());
        assertFalse(role.isClientRole());
    }

    @Test
    void testIsRealmRole_false() {
        RoleDTO role = new RoleDTO();
        role.setTypeRole(TypeRole.CLIENT_ROLE);
        assertFalse(role.isRealmRole());
    }

    @Test
    void testIsRealmRole_null() {
        RoleDTO role = new RoleDTO();
        role.setTypeRole(null);
        assertFalse(role.isRealmRole());
    }

    @Test
    void testIsClientRole_true() {
        RoleDTO role = new RoleDTO();
        role.setTypeRole(TypeRole.CLIENT_ROLE);
        assertTrue(role.isClientRole());
        assertFalse(role.isRealmRole());
    }

    @Test
    void testIsClientRole_false() {
        RoleDTO role = new RoleDTO();
        role.setTypeRole(TypeRole.REALM_ROLE);
        assertFalse(role.isClientRole());
    }

    @Test
    void testIsClientRole_null() {
        RoleDTO role = new RoleDTO();
        role.setTypeRole(null);
        assertFalse(role.isClientRole());
    }

    @Test
    void testIsComposite_withCompositeRoles() {
        RoleDTO role = new RoleDTO();
        role.setComposite(true);
        role.setCompositeRoles(Arrays.asList("role1", "role2"));
        assertTrue(role.isComposite());
    }

    @Test
    void testIsComposite_withCompositeRealmRoles() {
        RoleDTO role = new RoleDTO();
        role.setComposite(true);
        role.setCompositeRoles(null);
        role.setCompositeRealmRoles(Collections.singletonList(new RoleDTO.RoleCompositeDTO()));
        assertTrue(role.isComposite());
    }

    @Test
    void testIsComposite_withCompositeClientRoles() {
        RoleDTO role = new RoleDTO();
        role.setComposite(true);
        role.setCompositeRoles(null);
        role.setCompositeRealmRoles(null);
        Map<String, List<RoleDTO.RoleCompositeDTO>> clientRoles = new HashMap<>();
        clientRoles.put("client", Collections.singletonList(new RoleDTO.RoleCompositeDTO()));
        role.setCompositeClientRoles(clientRoles);
        assertTrue(role.isComposite());
    }

    @Test
    void testIsComposite_falseWhenCompositeFalse() {
        RoleDTO role = new RoleDTO();
        role.setComposite(false);
        role.setCompositeRoles(Arrays.asList("role1"));
        assertFalse(role.isComposite());
    }

    @Test
    void testIsComposite_falseWhenCompositeNull() {
        RoleDTO role = new RoleDTO();
        role.setComposite(null);
        role.setCompositeRoles(Arrays.asList("role1"));
        assertFalse(role.isComposite());
    }

    @Test
    void testIsComposite_falseWhenNoRoles() {
        RoleDTO role = new RoleDTO();
        role.setComposite(true);
        role.setCompositeRoles(null);
        role.setCompositeRealmRoles(null);
        role.setCompositeClientRoles(null);
        assertFalse(role.isComposite());
    }

    @Test
    void testIsComposite_falseWhenEmptyRoles() {
        RoleDTO role = new RoleDTO();
        role.setComposite(true);
        role.setCompositeRoles(Collections.emptyList());
        role.setCompositeRealmRoles(Collections.emptyList());
        role.setCompositeClientRoles(Collections.emptyMap());
        assertFalse(role.isComposite());
    }

    @Test
    void testGetFullName_realmRole() {
        RoleDTO role = new RoleDTO();
        role.setName("admin");
        role.setTypeRole(TypeRole.REALM_ROLE);
        assertEquals("admin", role.getFullName());
    }

    @Test
    void testGetFullName_clientRole() {
        RoleDTO role = new RoleDTO();
        role.setName("admin");
        role.setTypeRole(TypeRole.CLIENT_ROLE);
        role.setClientName("app");
        assertEquals("app:admin", role.getFullName());
    }

    @Test
    void testGetFullName_clientRoleNullClientName() {
        RoleDTO role = new RoleDTO();
        role.setName("admin");
        role.setTypeRole(TypeRole.CLIENT_ROLE);
        role.setClientName(null);
        assertEquals("admin", role.getFullName());
    }

    @Test
    void testGetFullName_nullTypeRole() {
        RoleDTO role = new RoleDTO();
        role.setName("admin");
        role.setTypeRole(null);
        assertEquals("admin", role.getFullName());
    }

    @Test
    void testRoleCompositeDTO_builder() {
        RoleDTO.RoleCompositeDTO comp = RoleDTO.RoleCompositeDTO.builder()
                .id("1")
                .name("role")
                .description("desc")
                .typeRole(TypeRole.REALM_ROLE)
                .clientName("client")
                .build();

        assertEquals("1", comp.getId());
        assertEquals("role", comp.getName());
        assertEquals("desc", comp.getDescription());
        assertEquals(TypeRole.REALM_ROLE, comp.getTypeRole());
        assertEquals("client", comp.getClientName());
    }

    @Test
    void testRoleCompositeDTO_settersGetters() {
        RoleDTO.RoleCompositeDTO comp = new RoleDTO.RoleCompositeDTO();
        comp.setId("id");
        comp.setName("name");
        comp.setDescription("desc");
        comp.setTypeRole(TypeRole.CLIENT_ROLE);
        comp.setClientName("client");

        assertEquals("id", comp.getId());
        assertEquals("name", comp.getName());
        assertEquals("desc", comp.getDescription());
        assertEquals(TypeRole.CLIENT_ROLE, comp.getTypeRole());
        assertEquals("client", comp.getClientName());
    }

    @Test
    void testRoleCompositeDTO_allArgsConstructor() {
        RoleDTO.RoleCompositeDTO comp = new RoleDTO.RoleCompositeDTO("id", "name", "desc", TypeRole.REALM_ROLE,
                "client");
        assertEquals("id", comp.getId());
        assertEquals("name", comp.getName());
        assertEquals("desc", comp.getDescription());
        assertEquals(TypeRole.REALM_ROLE, comp.getTypeRole());
        assertEquals("client", comp.getClientName());
    }

    @Test
    void testRoleCompositeDTO_equalsAndHashCode() {
        RoleDTO.RoleCompositeDTO comp1 = RoleDTO.RoleCompositeDTO.builder().id("1").name("role").build();
        RoleDTO.RoleCompositeDTO comp2 = RoleDTO.RoleCompositeDTO.builder().id("1").name("role").build();
        RoleDTO.RoleCompositeDTO comp3 = RoleDTO.RoleCompositeDTO.builder().id("2").name("other").build();

        assertEquals(comp1, comp2);
        assertEquals(comp1.hashCode(), comp2.hashCode());
        assertNotEquals(comp1, comp3);
    }

    @Test
    void testRoleCompositeDTO_toString() {
        RoleDTO.RoleCompositeDTO comp = RoleDTO.RoleCompositeDTO.builder().id("1").name("role").build();
        String str = comp.toString();
        assertNotNull(str);
        assertTrue(str.contains("role"));
    }

    @Test
    void testBuilderAndAllFields() {
        Map<String, List<String>> attrs = new HashMap<>();
        attrs.put("key", Collections.singletonList("value"));
        Map<String, List<RoleDTO.RoleCompositeDTO>> clientComposites = new HashMap<>();
        clientComposites.put("client",
                Collections.singletonList(RoleDTO.RoleCompositeDTO.builder().name("subclient").build()));

        RoleDTO role = RoleDTO.builder()
                .id("uuid-123")
                .name("admin")
                .description("Administrator role")
                .typeRole(TypeRole.REALM_ROLE)
                .composite(true)
                .containerId("container")
                .realmName("realm")
                .clientName("client")
                .clientId("clientId")
                .compositeRoles(Arrays.asList("role1", "role2"))
                .compositeRealmRoles(
                        Collections.singletonList(RoleDTO.RoleCompositeDTO.builder().name("subrealm").build()))
                .compositeClientRoles(clientComposites)
                .attributes(attrs)
                .userCount(10)
                .systemRole(false)
                .deletable(true)
                .build();

        assertEquals("uuid-123", role.getId());
        assertEquals("admin", role.getName());
        assertEquals("Administrator role", role.getDescription());
        assertEquals(TypeRole.REALM_ROLE, role.getTypeRole());
        assertTrue(role.getComposite());
        assertEquals("container", role.getContainerId());
        assertEquals("realm", role.getRealmName());
        assertEquals("client", role.getClientName());
        assertEquals("clientId", role.getClientId());
        assertEquals(2, role.getCompositeRoles().size());
        assertEquals(1, role.getCompositeRealmRoles().size());
        assertEquals(1, role.getCompositeClientRoles().size());
        assertEquals(1, role.getAttributes().size());
        assertEquals(10, role.getUserCount());
        assertFalse(role.getSystemRole());
        assertTrue(role.getDeletable());
    }

    @Test
    void testEqualsAndHashCode() {
        RoleDTO role1 = RoleDTO.builder().id("uuid-123").name("admin").build();
        RoleDTO role2 = RoleDTO.builder().id("uuid-123").name("admin").build();
        RoleDTO role3 = RoleDTO.builder().id("uuid-456").name("user").build();

        assertEquals(role1, role2);
        assertEquals(role1.hashCode(), role2.hashCode());
        assertNotEquals(role1, role3);
    }

    @Test
    void testToString() {
        RoleDTO role = RoleDTO.builder().name("admin").description("Admin role").build();
        String str = role.toString();
        assertNotNull(str);
        assertTrue(str.contains("admin"));
    }

    @Test
    void testNoArgsConstructor() {
        RoleDTO role = new RoleDTO();
        assertNull(role.getName());
        assertNull(role.getDescription());
    }

    @Test
    void testAllArgsConstructor() {
        Map<String, List<String>> attrs = new HashMap<>();
        Map<String, List<RoleDTO.RoleCompositeDTO>> clientComposites = new HashMap<>();
        List<String> compositeRoles = Collections.emptyList();
        List<RoleDTO.RoleCompositeDTO> realmComposites = Collections.emptyList();

        RoleDTO role = new RoleDTO(
                "name", "desc", TypeRole.REALM_ROLE, true, "container", "realm",
                "clientName", "clientId", compositeRoles, realmComposites, clientComposites,
                attrs, 5, true, false);

        assertEquals("name", role.getName());
        assertEquals("desc", role.getDescription());
        assertEquals(TypeRole.REALM_ROLE, role.getTypeRole());
        assertTrue(role.getComposite());
        assertEquals("container", role.getContainerId());
        assertEquals("realm", role.getRealmName());
        assertEquals("clientName", role.getClientName());
        assertEquals("clientId", role.getClientId());
        assertEquals(5, role.getUserCount());
        assertTrue(role.getSystemRole());
        assertFalse(role.getDeletable());
    }
}
