package puzzle;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import puzzle.Masker.Clues;
import puzzle.SwedishGenerator.Rng;
import static puzzle.SwedishGenerator.STACK_SIZE;

public class ConnectivityTest {

    @Test
    void testConnectivityPenalty() {
        Rng rng = new Rng(42);
        Masker masker = new Masker(rng, new int[STACK_SIZE], Clues.createEmpty());
        
        // 1. Maak een masker met één component van clues (bijv. 2 clues die elkaar kruisen)
        Clues singleComp = Clues.createEmpty();
        // Clue 1: (0,0) Right. Slot: (0,1), (0,2), (0,3)
        // Clue 2: (1,2) Up. Slot: (0,2)
        // Ze zijn NIET 8-naburig, maar wel verbonden via slot op (0,2)
        singleComp.setClueLo(1L << SwedishGenerator.Grid.offset(0,0), (byte)1); 
        singleComp.setClueLo(1L << SwedishGenerator.Grid.offset(2,2), (byte)2); // Up van (2,2) naar (1,2), (0,2)
        
        long fitnessSingle = masker.maskFitness(singleComp, 2);
        
        // 2. Maak een masker met twee eilandjes van clues
        Clues twoIslands = Clues.createEmpty();
        twoIslands.setClueLo(1L << SwedishGenerator.Grid.offset(0,0), (byte)1);
        twoIslands.setClueLo( SwedishGenerator.Grid.offset(7,7) < 64 ? 1L << SwedishGenerator.Grid.offset(7,7) : 0, (byte)1);
        // Voor de zekerheid checken we of offset(7,7) in lo of hi zit
        int off77 = SwedishGenerator.Grid.offset(7,7);
        if (off77 < 64) twoIslands.setClueLo(1L << off77, (byte)1);
        else twoIslands.setClueHi(1L << (off77 - 64), (byte)1);
        
        long fitnessIslands = masker.maskFitness(twoIslands, 2);
        
        System.out.println("[DEBUG_LOG] Fitness single component: " + fitnessSingle);
        System.out.println("[DEBUG_LOG] Fitness two islands: " + fitnessIslands);
        
        assertTrue(fitnessIslands > fitnessSingle + 10000, "Islands should have much higher penalty");
    }
    
    @Test
    void testPhysicalAdjacency() {
        Rng rng = new Rng(42);
        Masker masker = new Masker(rng, new int[STACK_SIZE], Clues.createEmpty());
        
        Clues clues = Clues.createEmpty();
        // Twee clues naast elkaar, maar slots kruisen niet.
        // Clue 1: (1,1) Right. Slot (1,2), (1,3), (1,4)
        // Clue 2: (2,1) Right. Slot (2,2), (2,3), (2,4)
        clues.setClueLo(1L << SwedishGenerator.Grid.offset(1,1), (byte)1);
        clues.setClueLo(1L << SwedishGenerator.Grid.offset(2,1), (byte)1);
        
        long fitness = masker.maskFitness(clues, 2);
        
        // Als 8-naburigheid NIET MEER meetelt, moet de penalty hoog zijn.
        System.out.println("[DEBUG_LOG] Fitness physically adjacent: " + fitness);
        assertTrue(fitness > 20000, "Should have island penalty even if physically adjacent");
    }
    
    @Test
    void testCornerClueConnectivity() {
        Rng rng = new Rng(42);
        Masker masker = new Masker(rng, new int[STACK_SIZE], Clues.createEmpty());
        
        Clues clues = Clues.createEmpty();
        // Clue A: (2,0) Right. Slot: (2,1), (2,2), (2,3), ...
        // Clue B: (1,2) Corner Down. Word starts at (1,3) en gaat omlaag: (1,3), (2,3), (3,3)...
        // Ze kruisen op (2,3).
        clues.setClueLo(1L << SwedishGenerator.Grid.offset(2,0), (byte)1); // Right
        clues.setClueLo(1L << SwedishGenerator.Grid.offset(1,2), (byte)4); // Corner Down
        
        long fitness = masker.maskFitness(clues, 2);
        System.out.println("[DEBUG_LOG] Fitness corner clue connected: " + fitness);
        
        // Als ze verbonden zijn, is de penalty voor eilandjes 0.
        // We vergelijken met een island scenario (2 clues die elkaar NIET raken)
        Clues island = Clues.createEmpty();
        int offA = SwedishGenerator.Grid.offset(2,0);
        if (offA < 64) island.setClueLo(1L << offA, (byte)1);
        else island.setClueHi(1L << (offA - 64), (byte)1);
        
        int offB = SwedishGenerator.Grid.offset(7,7);
        if (offB < 64) island.setClueLo(1L << offB, (byte)1);
        else island.setClueHi(1L << (offB - 64), (byte)1);
        
        long fitnessIsland = masker.maskFitness(island, 2);
        System.out.println("[DEBUG_LOG] Fitness island: " + fitnessIsland);
        
        assertTrue(fitnessIsland > fitness + 20000, "Island should add significant penalty compared to connected corner clue");
    }
}
