package puzzle;

import lombok.val;
import puzzle.DictJavaGeneratorMulti.CsvIndexService;
import puzzle.Meta.ShardRec;
import puzzle.SwedishGenerator.Lemma;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import static java.nio.charset.StandardCharsets.US_ASCII;
public class BuildClueAndSimpelIndex {
   
   public static void main(String[] args) throws Exception {
      val records = buildDict(Path.of("nl_score_hints_v4.csv"));
      
      buildShard(records);
      
      for (var qRaw : List.of("FIETS", "HUIS", "KIWI")) {
         var w = Lemma.from(qRaw);
         var i = Meta.findIndexInMapMmap(w);
         
         System.out.println("\nQuery: " + qRaw + " (norm=" + qRaw + ") w=" + w + " -> i=" + i);
         if (i >= 0) {
            var rec = Meta.readRecord(w, i);
            System.out.println("  simpel=" + rec.simpel());
            System.out.println("  clues=" + Arrays.toString(rec.clues()));
         } else {
            System.out.println("  NOT FOUND");
         }
      }
      
      System.out.println("\nFiles written to: " + Meta.dir);
      System.out.println("  " + Meta.shardData);
      System.out.println("  " + Meta.shardMap);
   }   // --- Demo main ---
   // --- Build demo files: shard.data + shard.map ---
   static void buildShard(List<ShardRec> records) throws IOException {
      records = new ArrayList<>(records);
      // map is sorted by w; record index i == positie in deze gesorteerde lijst
      records.sort(Comparator.comparingLong(ShardRec::w));
      
      var          n        = records.size();
      List<byte[]> recBytes = new ArrayList<>(n);
      var          offsets  = new int[n];
      
      var off = 0;
      for (var i = 0; i < n; i++) {
         var r = records.get(i);
         // schrijf het echte woord weg + simpel + JSON hints
         var line  = r.word() + "\t" + r.simpel() + "\t" + Meta.GSON.toJson(r.clues());
         var bytes = line.getBytes(StandardCharsets.UTF_8);
         recBytes.add(bytes);
         offsets[i] = off;
         
         off += bytes.length;
      }
      
      var headerSize = 12L;
      var tableSize  = (long) n * 4L;
      var dataStart  = headerSize + tableSize;
      
      try (var ch = FileChannel.open(Meta.shardData, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE)) {
         
         var hdr = ByteBuffer.allocate(12).order(Meta.ORDER);
         hdr.putInt(Meta.SHARD_MAGIC).putInt(Meta.VERSION).putInt(n);
         hdr.flip();
         ch.write(hdr);
         
         var table = ByteBuffer.allocate(n * 4).order(Meta.ORDER);
         for (var i = 0; i < n; i++) table.putInt(offsets[i]);
         table.flip();
         ch.write(table);
         
         ch.position(dataStart);
         for (var b : recBytes) ch.write(ByteBuffer.wrap(b));
      }
      
      try (var ch = FileChannel.open(Meta.shardMap, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE)) {
         
         var hdr = ByteBuffer.allocate(12).order(Meta.ORDER);
         hdr.putInt(Meta.MAP_MAGIC).putInt(Meta.VERSION).putInt(n);
         hdr.flip();
         ch.write(hdr);
         
         var keys = ByteBuffer.allocate(n * 8).order(Meta.ORDER);
         for (var r : records) keys.putLong(r.w());
         keys.flip();
         ch.write(keys);
      }
   }
   private static List<ShardRec> buildDict(Path wordsPath) throws IOException {
      var recs = new ArrayList<ShardRec>();
      try (var lines = Files.lines(wordsPath, StandardCharsets.UTF_8)) {
         lines.forEach(line -> {
            var  parts = line.split(",", 4);
            var  word  = parts[0].trim();
            long w     = SwedishGenerator.Lemma.from(word.getBytes(US_ASCII));
            if (!word.equals(SwedishGenerator.Lemma.asWord(w, Export.BYTES.get()))) {
               throw new RuntimeException();
            }
            var rawClue = parts[3].trim();
            if (rawClue.startsWith("\"") && rawClue.endsWith("\"")) {
               rawClue = rawClue.substring(1, rawClue.length() - 1).replace("\"\"", "\"");
            }
            var clues  = Meta.GSON.fromJson(rawClue, String[].class);
            var simpel = Integer.parseInt(parts[CsvIndexService.SIMPEL_IDX].trim());
            recs.add(new ShardRec(word, w, simpel, clues));
         });
      }
      return recs;
   }
}
