import "dart:typed_data";
import "package:flat_buffers/flat_buffers.dart" as fb;
import "package:only_bible_app/bible_data.dart";
// Converts bible .txt to FlatBuffer binary
// Format: bookName|bookIndex|chapterIndex|verseNo|heading|headingReferences|text...
Uint8List convertBibleToFlatBuffer(BibleItem item, String text) {
final books = <int, Map<int, List<Map<String, dynamic>>>>{};
final bookNames = <int, String>{};
final lines = text.split("\n");
for (var i = 0; i < lines.length; i++) {
if (line.isEmpty) continue;
final arr = line.split("|");
// bookName|bookIndex|chapterIndex|verseNo|heading|headingReferences|text...
final book = int.parse(arr[1]);
final chapter = int.parse(arr[2]);
final verseNo = int.parse(arr[3]);
final headingReferences = arr[5];
final verseText = arr.sublist(6).join("|");
bookNames.putIfAbsent(book, () => bookName);
books.putIfAbsent(book, () => {});
books[book]!.putIfAbsent(chapter, () => []);
books[book]![chapter]!.add({
"heading_references": headingReferences,
final rfPattern = RegExp(r"RF:(\d+):(\d+):(\d+)");
final builder = fb.Builder(initialSize: 1024 * 1024);
final bookOffsets = <int>[];
final sortedBooks = books.keys.toList()..sort();
for (final bookIdx in sortedBooks) {
final chapters = books[bookIdx]!;
final chapterOffsets = <int>[];
final sortedChapters = chapters.keys.toList()..sort();
for (final chapterIdx in sortedChapters) {
final verses = chapters[chapterIdx]!;
final verseOffsets = <int>[];
for (final v in verses) {
final headingOffset = builder.writeString(v["heading"] as String);
final textOffset = builder.writeString(v["text"] as String);
// Parse heading_references string into Reference tables
final refStr = v["heading_references"] as String;
final refOffsets = <int>[];
for (final match in rfPattern.allMatches(refStr)) {
builder.addInt32(0, int.parse(match.group(1)!));
builder.addInt32(1, int.parse(match.group(2)!));
builder.addInt32(2, int.parse(match.group(3)!));
refOffsets.add(builder.endTable());
if (refOffsets.isNotEmpty) {
refsVectorOffset = builder.writeList(refOffsets);
builder.addInt32(0, v["index"] as int);
builder.addInt32(1, v["book"] as int);
builder.addInt32(2, v["chapter"] as int);
builder.addOffset(3, headingOffset);
if (refsVectorOffset != null) {
builder.addOffset(4, refsVectorOffset);
builder.addOffset(5, textOffset);
verseOffsets.add(builder.endTable());
final versesVectorOffset = builder.writeList(verseOffsets);
builder.addInt32(0, chapterIdx);
builder.addInt32(1, bookIdx);
builder.addOffset(2, versesVectorOffset);
chapterOffsets.add(builder.endTable());
final chaptersVectorOffset = builder.writeList(chapterOffsets);
final bookNameOffset = builder.writeString(bookNames[bookIdx]!);
builder.addInt32(0, bookIdx);
builder.addOffset(1, bookNameOffset);
builder.addOffset(2, chaptersVectorOffset);
bookOffsets.add(builder.endTable());
final booksVectorOffset = builder.writeList(bookOffsets);
final nameOffset = builder.writeString(item.fileName);
final languageCodeOffset = builder.writeString(item.languageCode);
final languageEnglishOffset = builder.writeString(item.languageEnglish);
final languageNativeOffset = builder.writeString(item.languageNative);
final voiceNameOffset = builder.writeString(item.voiceName);
final oldTestamentTitleOffset = builder.writeString(item.oldTestamentTitle);
final newTestamentTitleOffset = builder.writeString(item.newTestamentTitle);
final bibleSelectTitleOffset = builder.writeString(item.bibleSelectTitle);
final themeTitleOffset = builder.writeString(item.themeTitle);
final boldFontTitleOffset = builder.writeString(item.boldFontTitle);
final engTitlesOffset = builder.writeString(item.engTitles);
final settingsTitleOffset = builder.writeString(item.settingsTitle);
builder.addOffset(0, nameOffset);
builder.addOffset(1, languageCodeOffset);
builder.addOffset(2, languageEnglishOffset);
builder.addOffset(3, languageNativeOffset);
builder.addOffset(4, voiceNameOffset);
builder.addOffset(5, oldTestamentTitleOffset);
builder.addOffset(6, newTestamentTitleOffset);
builder.addOffset(7, bibleSelectTitleOffset);
builder.addOffset(8, themeTitleOffset);
builder.addOffset(9, boldFontTitleOffset);
builder.addOffset(10, engTitlesOffset);
builder.addOffset(11, settingsTitleOffset);
builder.addOffset(12, booksVectorOffset);
final bibleOffset = builder.endTable();
builder.finish(bibleOffset);
final biblesDir = Directory("scripts/files");
final txtFiles = biblesDir.listSync().whereType<File>().where((f) => f.path.endsWith(".txt"));
for (final file in txtFiles) {
final fileName = file.uri.pathSegments.last.replaceAll(".txt", "");
final item = bibleItems[fileName];
print("Skipping $fileName: no matching BibleItem");
final text = await file.readAsString(encoding: utf8);
final bytes = convertBibleToFlatBuffer(item, text);
final compressed = gzip.encode(bytes);
final outPath = "assets/bibles/$fileName.bin.gz";
await File(outPath).writeAsBytes(compressed);
final txtSize = (file.lengthSync() / 1024).toStringAsFixed(1);
final binSize = (compressed.length / 1024).toStringAsFixed(1);
print("$fileName: ${txtSize}KB txt -> ${binSize}KB bin");
print("Done! Generated ${txtFiles.length} .bin files.");