package puzzle;

import org.junit.jupiter.api.Test;
import puzzle.Export.Gridded;
import puzzle.Export.Placed;
import puzzle.Export.Rewards;
import puzzle.Export.PuzzleResult;
import puzzle.SwedishGenerator.FillResult;
import puzzle.SwedishGenerator.Grid;
import puzzle.SwedishGenerator.Lemma;
import puzzle.SwedishGenerator.Rng;

import java.util.HashMap;

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

public class ExportFormatTest {
   
   @Test
   void testExportFormatFromFilled() {
      var swe  = new SwedishGenerator(new Rng(0));
      var grid = Grid.createEmpty();
      
      // Place a '2' (right) at (0,0)
      grid.setClue(0, (byte) '2');
      // This creates a slot starting at (0,1)
      
      var clueMap = new HashMap<Integer, Lemma>();
      // key = (cellIndex << 4) | direction
      var key   = (0 << 4) | 2;
      var lemma = new Lemma("TEST", 1, "A test word");
      clueMap.put(key, lemma);
      
      // Manually fill the grid letters for "TEST" at (0,1), (0,2), (0,3), (0,4)
      grid.setByteAt(Grid.offset(0, 1), (byte) 'T');
      grid.setByteAt(Grid.offset(0, 2), (byte) 'E');
      grid.setByteAt(Grid.offset(0, 3), (byte) 'S');
      grid.setByteAt(Grid.offset(0, 4), (byte) 'T');
      // Terminate thGrid.offset(e slot at) (0,5) with another digit to avoid it extending to MAX_WORD_LENGTH
      grid.setClue(Grid.offset(0, 5), (byte) '1');
      
      var fillResult   = new FillResult(true, new Gridded(grid), clueMap, new FillStats());
      var puzzleResult = new PuzzleResult(swe, null, null, fillResult);
      
      var rewards  = new Rewards(10, 5, 1);
      var exported = puzzleResult.exportFormatFromFilled(2, rewards);
      
      assertNotNull(exported);
      assertEquals(2, exported.difficulty());
      assertEquals(rewards, exported.rewards());
      
      // Check words
      assertEquals(1, exported.words().length);
      var w = exported.words()[0];
      assertEquals("TEST", w.word());
      assertEquals(Placed.HORIZONTAL, w.direction());
      
      // The bounding box should include (0,0) for the arrow and (0,1)-(0,4) for the word.
      // minR=0, maxR=0, minC=0, maxC=4
      // startRow = 0 - minR = 0
      // startCol = 1 - minC = 1
      assertEquals(0, w.startRow());
      assertEquals(1, w.startCol());
      assertEquals(0, w.arrowRow());
      assertEquals(0, w.arrowCol());
      
      // Check gridv2
      // It should be 1 row, containing "2TEST" -> but letters are mapped, digits are not explicitly in letterAt.
      // Wait, look at exportFormatFromFilled logic:
      // row.append(letterAt.getOrDefault(pack(r, c), '#'));
      // letterAt only contains letters from placed words.
      // arrow cells are NOT in letterAt unless they are also part of a word (unlikely).
      // So (0,0) should be '#'
      assertEquals(1, exported.gridv2().length);
      assertEquals("#TEST", exported.gridv2()[0]);
   }
   
   @Test
   void testExportFormatEmpty() {
      var swe          = new SwedishGenerator(new Rng(0));
      var grid         = Grid.createEmpty();
      var fillResult   = new FillResult(true, new Gridded(grid), new HashMap<>(), new FillStats());
      var puzzleResult = new PuzzleResult(swe, null, null, fillResult);
      
      var exported = puzzleResult.exportFormatFromFilled(1, new Rewards(0, 0, 0));
      
      assertNotNull(exported);
      assertEquals(0, exported.words().length);
      // Should return full grid with '#'
      assertEquals(R, exported.gridv2().length);
      for (var row : exported.gridv2()) {
         assertEquals(C, row.length());
         assertTrue(row.matches("#+"));
      }
   }
}
