package com.livingworld.regions;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertTrue;

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

/**
 * Unit tests for {@link RegionFlags}.
 */
class RegionFlagsTest {

    // ------------------------------------------------------------------
    // Default values
    // ------------------------------------------------------------------

    @Nested
    @DisplayName("Default values")
    class DefaultValues {

        @Test
        void allFlagsDefaultToFalse() {
            RegionFlags flags = new RegionFlags();
            assertFalse(flags.isHasPlayerActivity());
            assertFalse(flags.isHasHighPollution());
            assertFalse(flags.isHasLowSoilQuality());
            assertFalse(flags.isHasActiveEcosystemEvent());
            assertFalse(flags.isForceLoadedBySimulation());
            assertFalse(flags.isCorrupted());
        }

        @Test
        void instanceIsNotNull() {
            assertNotNull(new RegionFlags());
        }
    }

    // ------------------------------------------------------------------
    // Getters and Setters
    // ------------------------------------------------------------------

    @Nested
    @DisplayName("Getters and Setters")
    class GetterSetterTests {

        @Test
        void hasPlayerActivity() {
            RegionFlags flags = new RegionFlags();
            flags.setHasPlayerActivity(true);
            assertTrue(flags.isHasPlayerActivity());
            flags.setHasPlayerActivity(false);
            assertFalse(flags.isHasPlayerActivity());
        }

        @Test
        void hasHighPollution() {
            RegionFlags flags = new RegionFlags();
            flags.setHasHighPollution(true);
            assertTrue(flags.isHasHighPollution());
            flags.setHasHighPollution(false);
            assertFalse(flags.isHasHighPollution());
        }

        @Test
        void hasLowSoilQuality() {
            RegionFlags flags = new RegionFlags();
            flags.setHasLowSoilQuality(true);
            assertTrue(flags.isHasLowSoilQuality());
            flags.setHasLowSoilQuality(false);
            assertFalse(flags.isHasLowSoilQuality());
        }

        @Test
        void hasActiveEcosystemEvent() {
            RegionFlags flags = new RegionFlags();
            flags.setHasActiveEcosystemEvent(true);
            assertTrue(flags.isHasActiveEcosystemEvent());
            flags.setHasActiveEcosystemEvent(false);
            assertFalse(flags.isHasActiveEcosystemEvent());
        }

        @Test
        void forceLoadedBySimulation() {
            RegionFlags flags = new RegionFlags();
            flags.setForceLoadedBySimulation(true);
            assertTrue(flags.isForceLoadedBySimulation());
            flags.setForceLoadedBySimulation(false);
            assertFalse(flags.isForceLoadedBySimulation());
        }

        @Test
        void corrupted() {
            RegionFlags flags = new RegionFlags();
            flags.setCorrupted(true);
            assertTrue(flags.isCorrupted());
            flags.setCorrupted(false);
            assertFalse(flags.isCorrupted());
        }
    }

    // ------------------------------------------------------------------
    // copy()
    // ------------------------------------------------------------------

    @Nested
    @DisplayName("copy()")
    class CopyTests {

        @Test
        void copyReturnsIndependentInstance() {
            RegionFlags original = new RegionFlags();
            original.setHasPlayerActivity(true);
            original.setCorrupted(true);

            RegionFlags copy = original.copy();
            assertNotNull(copy);
            assertNotSame(original, copy);
        }

        @Test
        void copyPreservesAllFlagValues() {
            RegionFlags original = new RegionFlags();
            original.setHasPlayerActivity(true);
            original.setHasHighPollution(true);
            original.setHasLowSoilQuality(true);
            original.setHasActiveEcosystemEvent(true);
            original.setForceLoadedBySimulation(true);
            original.setCorrupted(true);

            RegionFlags copy = original.copy();
            assertTrue(copy.isHasPlayerActivity());
            assertTrue(copy.isHasHighPollution());
            assertTrue(copy.isHasLowSoilQuality());
            assertTrue(copy.isHasActiveEcosystemEvent());
            assertTrue(copy.isForceLoadedBySimulation());
            assertTrue(copy.isCorrupted());
        }

        @Test
        void modifyingCopyDoesNotAffectOriginal() {
            RegionFlags original = new RegionFlags();
            original.setHasPlayerActivity(true);
            original.setCorrupted(false);

            RegionFlags copy = original.copy();
            copy.setHasPlayerActivity(false);
            copy.setCorrupted(true);

            assertTrue(original.isHasPlayerActivity());
            assertFalse(original.isCorrupted());
        }
    }

    // ------------------------------------------------------------------
    // clearTransientFlags()
    // ------------------------------------------------------------------

    @Nested
    @DisplayName("clearTransientFlags()")
    class ClearTransientFlagTests {

        @Test
        void clearsTransientFlagsOnly() {
            RegionFlags flags = new RegionFlags();
            flags.setHasPlayerActivity(true);
            flags.setHasActiveEcosystemEvent(true);
            flags.setHasHighPollution(true);
            flags.setHasLowSoilQuality(true);
            flags.setForceLoadedBySimulation(true);
            flags.setCorrupted(true);

            flags.clearTransientFlags();

            // Transient flags cleared
            assertFalse(flags.isHasPlayerActivity());
            assertFalse(flags.isHasActiveEcosystemEvent());

            // Persistent flags preserved
            assertTrue(flags.isHasHighPollution());
            assertTrue(flags.isHasLowSoilQuality());
            assertTrue(flags.isForceLoadedBySimulation());
            assertTrue(flags.isCorrupted());
        }

        @Test
        void safeToCallWhenAllFlagsAlreadyFalse() {
            RegionFlags flags = new RegionFlags();
            flags.clearTransientFlags(); // should not throw
            assertFalse(flags.isHasPlayerActivity());
            assertFalse(flags.isHasActiveEcosystemEvent());
        }
    }

    // ------------------------------------------------------------------
    // toString
    // ------------------------------------------------------------------

    @Nested
    @DisplayName("toString")
    class ToStringTests {

        @Test
        void toStringContainsFlagNames() {
            RegionFlags flags = new RegionFlags();
            flags.setHasPlayerActivity(true);
            String s = flags.toString();
            assertTrue(s.contains("hasPlayerActivity=true"));
            assertTrue(s.contains("corrupted=false"));
        }
    }
}