package dev.lions.unionflow.server.entity;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.time.LocalDateTime;
import java.util.UUID;

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

@DisplayName("SystemAlert entity")
class SystemAlertTest {

    // -------------------------------------------------------------------------
    // No-args constructor
    // -------------------------------------------------------------------------
    @Test
    @DisplayName("no-args constructor creates instance with default acknowledged=false")
    void noArgsConstructor_defaultAcknowledgedFalse() {
        SystemAlert alert = new SystemAlert();

        assertThat(alert).isNotNull();
        // Field initialiser on the declaration sets it to false
        assertThat(alert.getAcknowledged()).isFalse();
        assertThat(alert.getLevel()).isNull();
        assertThat(alert.getTitle()).isNull();
        assertThat(alert.getMessage()).isNull();
        assertThat(alert.getTimestamp()).isNull();
        assertThat(alert.getAcknowledgedBy()).isNull();
        assertThat(alert.getAcknowledgedAt()).isNull();
        assertThat(alert.getSource()).isNull();
        assertThat(alert.getAlertType()).isNull();
        assertThat(alert.getCurrentValue()).isNull();
        assertThat(alert.getThresholdValue()).isNull();
        assertThat(alert.getUnit()).isNull();
        assertThat(alert.getRecommendedActions()).isNull();
    }

    // -------------------------------------------------------------------------
    // Getters / Setters — every field
    // -------------------------------------------------------------------------
    @Nested
    @DisplayName("Getters and Setters")
    class GettersSettersTests {

        @Test
        @DisplayName("setLevel / getLevel round-trips")
        void level_roundTrips() {
            SystemAlert alert = new SystemAlert();
            alert.setLevel("CRITICAL");
            assertThat(alert.getLevel()).isEqualTo("CRITICAL");
        }

        @Test
        @DisplayName("setTitle / getTitle round-trips")
        void title_roundTrips() {
            SystemAlert alert = new SystemAlert();
            alert.setTitle("CPU très élevé");
            assertThat(alert.getTitle()).isEqualTo("CPU très élevé");
        }

        @Test
        @DisplayName("setMessage / getMessage round-trips")
        void message_roundTrips() {
            SystemAlert alert = new SystemAlert();
            alert.setMessage("Utilisation CPU > 95% depuis 5 minutes");
            assertThat(alert.getMessage()).isEqualTo("Utilisation CPU > 95% depuis 5 minutes");
        }

        @Test
        @DisplayName("setTimestamp / getTimestamp round-trips")
        void timestamp_roundTrips() {
            LocalDateTime ts = LocalDateTime.of(2026, 4, 20, 12, 0, 0);
            SystemAlert alert = new SystemAlert();
            alert.setTimestamp(ts);
            assertThat(alert.getTimestamp()).isEqualTo(ts);
        }

        @Test
        @DisplayName("setAcknowledged true / getAcknowledged round-trips")
        void acknowledged_true_roundTrips() {
            SystemAlert alert = new SystemAlert();
            alert.setAcknowledged(true);
            assertThat(alert.getAcknowledged()).isTrue();
        }

        @Test
        @DisplayName("setAcknowledged false / getAcknowledged round-trips")
        void acknowledged_false_roundTrips() {
            SystemAlert alert = new SystemAlert();
            alert.setAcknowledged(false);
            assertThat(alert.getAcknowledged()).isFalse();
        }

        @Test
        @DisplayName("setAcknowledgedBy / getAcknowledgedBy round-trips")
        void acknowledgedBy_roundTrips() {
            SystemAlert alert = new SystemAlert();
            alert.setAcknowledgedBy("admin@unionflow.com");
            assertThat(alert.getAcknowledgedBy()).isEqualTo("admin@unionflow.com");
        }

        @Test
        @DisplayName("setAcknowledgedAt / getAcknowledgedAt round-trips")
        void acknowledgedAt_roundTrips() {
            LocalDateTime dt = LocalDateTime.of(2026, 4, 20, 12, 30, 0);
            SystemAlert alert = new SystemAlert();
            alert.setAcknowledgedAt(dt);
            assertThat(alert.getAcknowledgedAt()).isEqualTo(dt);
        }

        @Test
        @DisplayName("setSource / getSource round-trips")
        void source_roundTrips() {
            SystemAlert alert = new SystemAlert();
            alert.setSource("CPU");
            assertThat(alert.getSource()).isEqualTo("CPU");
        }

        @Test
        @DisplayName("setAlertType / getAlertType round-trips")
        void alertType_roundTrips() {
            SystemAlert alert = new SystemAlert();
            alert.setAlertType("THRESHOLD");
            assertThat(alert.getAlertType()).isEqualTo("THRESHOLD");
        }

        @Test
        @DisplayName("setCurrentValue / getCurrentValue round-trips")
        void currentValue_roundTrips() {
            SystemAlert alert = new SystemAlert();
            alert.setCurrentValue(97.5);
            assertThat(alert.getCurrentValue()).isEqualTo(97.5);
        }

        @Test
        @DisplayName("setThresholdValue / getThresholdValue round-trips")
        void thresholdValue_roundTrips() {
            SystemAlert alert = new SystemAlert();
            alert.setThresholdValue(90.0);
            assertThat(alert.getThresholdValue()).isEqualTo(90.0);
        }

        @Test
        @DisplayName("setUnit / getUnit round-trips")
        void unit_roundTrips() {
            SystemAlert alert = new SystemAlert();
            alert.setUnit("%");
            assertThat(alert.getUnit()).isEqualTo("%");
        }

        @Test
        @DisplayName("setRecommendedActions / getRecommendedActions round-trips")
        void recommendedActions_roundTrips() {
            SystemAlert alert = new SystemAlert();
            alert.setRecommendedActions("Redémarrer le service. Vérifier les logs.");
            assertThat(alert.getRecommendedActions()).isEqualTo("Redémarrer le service. Vérifier les logs.");
        }
    }

    // -------------------------------------------------------------------------
    // Typical alert level values
    // -------------------------------------------------------------------------
    @Test
    @DisplayName("level accepts all expected severity values")
    void level_acceptsAllSeverityValues() {
        String[] levels = {"CRITICAL", "ERROR", "WARNING", "INFO"};
        SystemAlert alert = new SystemAlert();
        for (String level : levels) {
            alert.setLevel(level);
            assertThat(alert.getLevel()).isEqualTo(level);
        }
    }

    // -------------------------------------------------------------------------
    // Typical source values
    // -------------------------------------------------------------------------
    @Test
    @DisplayName("source accepts typical metric sources")
    void source_acceptsTypicalSources() {
        String[] sources = {"CPU", "MEMORY", "DISK", "DATABASE"};
        SystemAlert alert = new SystemAlert();
        for (String source : sources) {
            alert.setSource(source);
            assertThat(alert.getSource()).isEqualTo(source);
        }
    }

    // -------------------------------------------------------------------------
    // UUID id (inherited from BaseEntity)
    // -------------------------------------------------------------------------
    @Test
    @DisplayName("UUID id field is settable and gettable")
    void uuidId_settableAndGettable() {
        UUID id = UUID.randomUUID();
        SystemAlert alert = new SystemAlert();
        alert.setId(id);
        assertThat(alert.getId()).isEqualTo(id);
    }

    // -------------------------------------------------------------------------
    // A complete "acknowledged alert" scenario
    // -------------------------------------------------------------------------
    @Test
    @DisplayName("full acknowledged alert scenario sets all fields coherently")
    void fullAcknowledgedAlertScenario() {
        LocalDateTime ts  = LocalDateTime.of(2026, 4, 20, 8, 0);
        LocalDateTime ack = LocalDateTime.of(2026, 4, 20, 8, 15);

        SystemAlert alert = new SystemAlert();
        alert.setLevel("WARNING");
        alert.setTitle("Mémoire élevée");
        alert.setMessage("Mémoire utilisée > 80%");
        alert.setTimestamp(ts);
        alert.setSource("MEMORY");
        alert.setAlertType("THRESHOLD");
        alert.setCurrentValue(83.2);
        alert.setThresholdValue(80.0);
        alert.setUnit("%");
        alert.setRecommendedActions("Libérer la mémoire ou augmenter la RAM.");
        alert.setAcknowledged(true);
        alert.setAcknowledgedBy("ops@unionflow.com");
        alert.setAcknowledgedAt(ack);

        assertThat(alert.getLevel()).isEqualTo("WARNING");
        assertThat(alert.getTitle()).isEqualTo("Mémoire élevée");
        assertThat(alert.getMessage()).isEqualTo("Mémoire utilisée > 80%");
        assertThat(alert.getTimestamp()).isEqualTo(ts);
        assertThat(alert.getSource()).isEqualTo("MEMORY");
        assertThat(alert.getAlertType()).isEqualTo("THRESHOLD");
        assertThat(alert.getCurrentValue()).isEqualTo(83.2);
        assertThat(alert.getThresholdValue()).isEqualTo(80.0);
        assertThat(alert.getUnit()).isEqualTo("%");
        assertThat(alert.getRecommendedActions()).contains("Libérer la mémoire");
        assertThat(alert.getAcknowledged()).isTrue();
        assertThat(alert.getAcknowledgedBy()).isEqualTo("ops@unionflow.com");
        assertThat(alert.getAcknowledgedAt()).isEqualTo(ack);
    }
}
