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

import org.junit.jupiter.api.Test;

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

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

class UserSearchResultDTOTest {

        @Test
        void testOf_firstPage() {
                List<UserDTO> users = Arrays.asList(
                                UserDTO.builder().username("user1").build(),
                                UserDTO.builder().username("user2").build());
                UserSearchCriteriaDTO criteria = UserSearchCriteriaDTO.builder()
                                .page(0)
                                .pageSize(10)
                                .build();

                UserSearchResultDTO result = UserSearchResultDTO.of(users, criteria, 25L);

                assertEquals(2, result.getUsers().size());
                assertEquals(25L, result.getTotalCount());
                assertEquals(0, result.getCurrentPage());
                assertEquals(10, result.getPageSize());
                assertEquals(3, result.getTotalPages());
                assertTrue(result.getHasNextPage());
                assertFalse(result.getHasPreviousPage());
                assertEquals(0, result.getFirstElement());
                assertEquals(9, result.getLastElement());
                assertFalse(result.getIsEmpty());
                assertTrue(result.getIsFirstPage());
                assertFalse(result.getIsLastPage());
                assertEquals(criteria, result.getCriteria());
        }

        @Test
        void testOf_middlePage() {
                List<UserDTO> users = Arrays.asList(
                                UserDTO.builder().username("user1").build());
                UserSearchCriteriaDTO criteria = UserSearchCriteriaDTO.builder()
                                .page(1)
                                .pageSize(10)
                                .build();

                UserSearchResultDTO result = UserSearchResultDTO.of(users, criteria, 25L);

                assertEquals(1, result.getCurrentPage());
                assertTrue(result.getHasNextPage());
                assertTrue(result.getHasPreviousPage());
                assertFalse(result.getIsFirstPage());
                assertFalse(result.getIsLastPage());
        }

        @Test
        void testOf_lastPage() {
                List<UserDTO> users = Arrays.asList(
                                UserDTO.builder().username("user1").build());
                UserSearchCriteriaDTO criteria = UserSearchCriteriaDTO.builder()
                                .page(2)
                                .pageSize(10)
                                .build();

                UserSearchResultDTO result = UserSearchResultDTO.of(users, criteria, 25L);

                assertEquals(2, result.getCurrentPage());
                assertFalse(result.getHasNextPage());
                assertTrue(result.getHasPreviousPage());
                assertFalse(result.getIsFirstPage());
                assertTrue(result.getIsLastPage());
        }

        @Test
        void testOf_emptyList() {
                List<UserDTO> users = Collections.emptyList();
                UserSearchCriteriaDTO criteria = UserSearchCriteriaDTO.builder()
                                .page(0)
                                .pageSize(20)
                                .build();

                UserSearchResultDTO result = UserSearchResultDTO.of(users, criteria, 0L);

                assertTrue(result.getIsEmpty());
                assertEquals(0, result.getTotalCount());
                assertEquals(0, result.getTotalPages());
        }

        @Test
        void testOf_nullList() {
                UserSearchCriteriaDTO criteria = UserSearchCriteriaDTO.builder()
                                .page(0)
                                .pageSize(20)
                                .build();

                UserSearchResultDTO result = UserSearchResultDTO.of(null, criteria, 0L);

                assertTrue(result.getIsEmpty());
        }

        @Test
        void testOf_singlePage() {
                List<UserDTO> users = Arrays.asList(
                                UserDTO.builder().username("user1").build());
                UserSearchCriteriaDTO criteria = UserSearchCriteriaDTO.builder()
                                .page(0)
                                .pageSize(10)
                                .build();

                UserSearchResultDTO result = UserSearchResultDTO.of(users, criteria, 5L);

                assertEquals(1, result.getTotalPages());
                assertFalse(result.getHasNextPage());
                assertFalse(result.getHasPreviousPage());
                assertTrue(result.getIsFirstPage());
                assertTrue(result.getIsLastPage());
        }

        @Test
        void testGetCurrentPageSize_withUsers() {
                UserSearchResultDTO result = UserSearchResultDTO.builder()
                                .users(Arrays.asList(
                                                UserDTO.builder().username("u1").build(),
                                                UserDTO.builder().username("u2").build(),
                                                UserDTO.builder().username("u3").build()))
                                .build();

                assertEquals(3, result.getCurrentPageSize());
        }

        @Test
        void testGetCurrentPageSize_emptyUsers() {
                UserSearchResultDTO result = UserSearchResultDTO.builder()
                                .users(Collections.emptyList())
                                .build();

                assertEquals(0, result.getCurrentPageSize());
        }

        @Test
        void testGetCurrentPageSize_nullUsers() {
                UserSearchResultDTO result = UserSearchResultDTO.builder()
                                .users(null)
                                .build();

                assertEquals(0, result.getCurrentPageSize());
        }

        @Test
        void testBuilderAndAllFields() {
                List<UserDTO> users = Collections.singletonList(UserDTO.builder().username("test").build());
                UserSearchCriteriaDTO criteria = UserSearchCriteriaDTO.builder().page(0).pageSize(20).build();

                UserSearchResultDTO result = UserSearchResultDTO.builder()
                                .users(users)
                                .totalCount(100L)
                                .currentPage(0)
                                .pageSize(20)
                                .totalPages(5)
                                .hasNextPage(true)
                                .hasPreviousPage(false)
                                .firstElement(0)
                                .lastElement(19)
                                .isEmpty(false)
                                .isFirstPage(true)
                                .isLastPage(false)
                                .criteria(criteria)
                                .executionTimeMs(150L)
                                .build();

                assertEquals(users, result.getUsers());
                assertEquals(100L, result.getTotalCount());
                assertEquals(0, result.getCurrentPage());
                assertEquals(20, result.getPageSize());
                assertEquals(5, result.getTotalPages());
                assertTrue(result.getHasNextPage());
                assertFalse(result.getHasPreviousPage());
                assertEquals(0, result.getFirstElement());
                assertEquals(19, result.getLastElement());
                assertFalse(result.getIsEmpty());
                assertTrue(result.getIsFirstPage());
                assertFalse(result.getIsLastPage());
                assertEquals(criteria, result.getCriteria());
                assertEquals(150L, result.getExecutionTimeMs());
        }

        @Test
        void testSettersAndGetters() {
                UserSearchResultDTO result = new UserSearchResultDTO();
                List<UserDTO> users = Collections.singletonList(UserDTO.builder().username("test").build());
                UserSearchCriteriaDTO criteria = UserSearchCriteriaDTO.builder().build();

                result.setUsers(users);
                result.setTotalCount(50L);
                result.setCurrentPage(1);
                result.setPageSize(10);
                result.setTotalPages(5);
                result.setHasNextPage(true);
                result.setHasPreviousPage(true);
                result.setFirstElement(10);
                result.setLastElement(19);
                result.setIsEmpty(false);
                result.setIsFirstPage(false);
                result.setIsLastPage(false);
                result.setCriteria(criteria);
                result.setExecutionTimeMs(200L);

                assertEquals(users, result.getUsers());
                assertEquals(50L, result.getTotalCount());
                assertEquals(1, result.getCurrentPage());
                assertEquals(10, result.getPageSize());
                assertEquals(5, result.getTotalPages());
                assertTrue(result.getHasNextPage());
                assertTrue(result.getHasPreviousPage());
                assertEquals(10, result.getFirstElement());
                assertEquals(19, result.getLastElement());
                assertFalse(result.getIsEmpty());
                assertFalse(result.getIsFirstPage());
                assertFalse(result.getIsLastPage());
                assertEquals(criteria, result.getCriteria());
                assertEquals(200L, result.getExecutionTimeMs());
        }

        @Test
        void testEqualsAndHashCode() {
                UserSearchResultDTO dto1 = UserSearchResultDTO.builder().totalCount(10L).currentPage(0).build();
                UserSearchResultDTO dto2 = UserSearchResultDTO.builder().totalCount(10L).currentPage(0).build();
                UserSearchResultDTO dto3 = UserSearchResultDTO.builder().totalCount(20L).currentPage(1).build();

                assertEquals(dto1, dto2);
                assertEquals(dto1.hashCode(), dto2.hashCode());
                assertNotEquals(dto1, dto3);
        }

        @Test
        void testToString() {
                UserSearchResultDTO result = UserSearchResultDTO.builder()
                                .totalCount(100L)
                                .currentPage(0)
                                .build();
                String str = result.toString();
                assertNotNull(str);
                assertTrue(str.contains("100"));
        }

        @Test
        void testNoArgsConstructor() {
                UserSearchResultDTO result = new UserSearchResultDTO();
                assertNull(result.getUsers());
                assertNull(result.getTotalCount());
                assertNull(result.getCurrentPage());
        }

        @Test
        void testAllArgsConstructor() {
                List<UserDTO> users = Collections.singletonList(UserDTO.builder().username("test").build());
                UserSearchCriteriaDTO criteria = UserSearchCriteriaDTO.builder().build();

                UserSearchResultDTO result = new UserSearchResultDTO(
                                users, 100L, 0, 20, 5, true, false, 0, 19, false, true, false, criteria, 150L);

                assertEquals(users, result.getUsers());
                assertEquals(100L, result.getTotalCount());
                assertEquals(0, result.getCurrentPage());
                assertEquals(20, result.getPageSize());
                assertEquals(5, result.getTotalPages());
                assertTrue(result.getHasNextPage());
                assertFalse(result.getHasPreviousPage());
                assertEquals(0, result.getFirstElement());
                assertEquals(19, result.getLastElement());
                assertFalse(result.getIsEmpty());
                assertTrue(result.getIsFirstPage());
                assertFalse(result.getIsLastPage());
                assertEquals(criteria, result.getCriteria());
                assertEquals(150L, result.getExecutionTimeMs());
        }
}
