package dev.lions.unionflow.server.api.dto.base;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.UUID;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

/**
 * Tests unitaires pour BaseResponse.
 * Couvre equals() et hashCode() basés sur l'ID.
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2026-03-01
 */
@DisplayName("Tests BaseResponse")
class BaseResponseTest {

    /** Sous-classe concrète pour tester BaseResponse (classe abstraite). */
    private static final class ConcreteBaseResponse extends BaseResponse {
        // aucune propriété additionnelle
    }

    @Nested
    @DisplayName("equals")
    class Equals {

        @Test
        @DisplayName("retourne true pour même instance")
        void testEqualsMemeInstance() {
            ConcreteBaseResponse response = new ConcreteBaseResponse();
            assertThat(response.equals(response)).isTrue();
        }

        @Test
        @DisplayName("retourne false pour null")
        void testEqualsNull() {
            ConcreteBaseResponse response = new ConcreteBaseResponse();
            assertThat(response.equals(null)).isFalse();
        }

        @Test
        @DisplayName("retourne false pour classe différente")
        void testEqualsClasseDifferente() {
            ConcreteBaseResponse response = new ConcreteBaseResponse();
            assertThat(response.equals("not a Response")).isFalse();
        }

        @Test
        @DisplayName("retourne true quand ids égaux (non null)")
        void testEqualsIdsEgaux() {
            UUID id = UUID.randomUUID();
            ConcreteBaseResponse a = new ConcreteBaseResponse();
            a.setId(id);
            ConcreteBaseResponse b = new ConcreteBaseResponse();
            b.setId(id);
            assertThat(a).isEqualTo(b);
        }

        @Test
        @DisplayName("retourne false quand id de this est null")
        void testEqualsIdThisNull() {
            ConcreteBaseResponse a = new ConcreteBaseResponse();
            a.setId(null);
            ConcreteBaseResponse b = new ConcreteBaseResponse();
            b.setId(UUID.randomUUID());
            assertThat(a.equals(b)).isFalse();
        }

        @Test
        @DisplayName("retourne false quand id de that est null")
        void testEqualsIdThatNull() {
            ConcreteBaseResponse a = new ConcreteBaseResponse();
            a.setId(UUID.randomUUID());
            ConcreteBaseResponse b = new ConcreteBaseResponse();
            b.setId(null);
            assertThat(a.equals(b)).isFalse();
        }

        @Test
        @DisplayName("retourne false quand les deux ids sont null")
        void testEqualsIdsDeuxNull() {
            ConcreteBaseResponse a = new ConcreteBaseResponse();
            a.setId(null);
            ConcreteBaseResponse b = new ConcreteBaseResponse();
            b.setId(null);
            assertThat(a.equals(b)).isFalse();
        }

        @Test
        @DisplayName("retourne false quand ids différents")
        void testEqualsIdsDifferents() {
            ConcreteBaseResponse a = new ConcreteBaseResponse();
            a.setId(UUID.randomUUID());
            ConcreteBaseResponse b = new ConcreteBaseResponse();
            b.setId(UUID.randomUUID());
            assertThat(a).isNotEqualTo(b);
        }
    }

    @Nested
    @DisplayName("hashCode")
    class HashCode {

        @Test
        @DisplayName("retourne 0 quand id est null")
        void testHashCodeIdNull() {
            ConcreteBaseResponse response = new ConcreteBaseResponse();
            assertThat(response.hashCode()).isEqualTo(0);
        }

        @Test
        @DisplayName("retourne id.hashCode() quand id non null")
        void testHashCodeIdNonNull() {
            UUID id = UUID.randomUUID();
            ConcreteBaseResponse response = new ConcreteBaseResponse();
            response.setId(id);
            assertThat(response.hashCode()).isEqualTo(id.hashCode());
        }

        @Test
        @DisplayName("objets égaux ont même hashCode")
        void testHashCodeConsistentAvecEquals() {
            UUID id = UUID.randomUUID();
            ConcreteBaseResponse a = new ConcreteBaseResponse();
            a.setId(id);
            ConcreteBaseResponse b = new ConcreteBaseResponse();
            b.setId(id);

            assertThat(a).isEqualTo(b);
            assertThat(a.hashCode()).isEqualTo(b.hashCode());
        }
    }
}
