import 'package:flutter/services.dart' show rootBundle;
import 'package:flutter/foundation.dart';
import 'package:xml/xml.dart';

// Helper for background XML parsing
XmlDocument parseXmlString(String xml) {
  return XmlDocument.parse(xml);
}

class BibleXmlParser {
  // Map of common Bible book names to their standard abbreviations or keys used in XML
  // This will help in matching references like "Matthew 11:28" to XML structure.
  static const Map<String, String> _bookAbbreviations = {
    'genesis': 'Gen', 'exodus': 'Exod', 'leviticus': 'Lev', 'numbers': 'Num',
    'deuteronomy': 'Deut', 'joshua': 'Josh', 'judges': 'Judg', 'ruth': 'Ruth',
    '1 samuel': '1Sam', '2 samuel': '2Sam', '1 kings': '1Kgs',
    '2 kings': '2Kgs',
    '1 chronicles': '1Chr', '2 chronicles': '2Chr', 'ezra': 'Ezra',
    'nehemiah': 'Neh',
    'esther': 'Esth', 'job': 'Job', 'psalm': 'Ps', 'proverbs': 'Prov',
    'ecclesiastes': 'Eccl', 'song of solomon': 'Song', 'isaiah': 'Isa',
    'jeremiah': 'Jer',
    'lamentations': 'Lam', 'ezekiel': 'Ezek', 'daniel': 'Dan', 'hosea': 'Hos',
    'joel': 'Joel', 'amos': 'Amos', 'obadiah': 'Obad', 'jonah': 'Jonah',
    'micah': 'Mic', 'nahum': 'Nah', 'habakkuk': 'Hab', 'zephaniah': 'Zeph',
    'haggai': 'Hag', 'zechariah': 'Zech', 'malachi': 'Mal',
    'matthew': 'Matt', 'mark': 'Mark', 'luke': 'Luke', 'john': 'John',
    'acts': 'Acts', 'romans': 'Rom', '1 corinthians': '1Cor',
    '2 corinthians': '2Cor',
    'galatians': 'Gal', 'ephesians': 'Eph', 'philippians': 'Phil',
    'colossians': 'Col',
    '1 thessalonians': '1Thess', '2 thessalonians': '2Thess',
    '1 timothy': '1Tim',
    '2 timothy': '2Tim', 'titus': 'Titus', 'philemon': 'Phlm', 'hebrews': 'Heb',
    'james': 'Jas', '1 peter': '1Pet', '2 peter': '2Pet', '1 john': '1John',
    '2 john': '2John', '3 john': '3John', 'jude': 'Jude', 'revelation': 'Rev',
    // Add more common names/abbreviations if necessary
  };

  /// Parses a Bible reference string (e.g., "Matthew 11:28") into its components.
  static Map<String, String>? parseReference(String reference) {
    final parts = reference.split(' ');
    if (parts.length < 2) return null; // Needs at least Book and Chapter:Verse

    String book = parts.sublist(0, parts.length - 1).join(' ').toLowerCase();
    String chapterVerse = parts.last;

    final chapterVerseParts = chapterVerse.split(':');
    if (chapterVerseParts.length != 2) return null; // Must have Chapter:Verse

    return {
      'book': book,
      'chapter': chapterVerseParts[0],
      'verse': chapterVerseParts[1],
    };
  }

  // Cache for parsed XML documents to avoid reloading/reparsing
  static final Map<String, XmlDocument> _xmlCache = {};

  /// Loads an XML Bible file from assets and returns the parsed document.
  Future<XmlDocument> loadXmlAsset(String assetPath) async {
    if (_xmlCache.containsKey(assetPath)) {
      return _xmlCache[assetPath]!;
    }

    debugPrint('Loading and parsing XML asset: $assetPath'); // Debug log
    final String xmlString = await rootBundle.loadString(assetPath);
    final document = await compute(parseXmlString, xmlString);
    _xmlCache[assetPath] = document;
    return document;
  }

  /// Extracts a specific verse from a parsed XML document.
  /// Supports two schemas:
  /// 1. <XMLBIBLE><BIBLEBOOK bname="..."><CHAPTER cnumber="..."><VERS vnumber="...">
  /// 2. <bible><b n="..."><c n="..."><v n="...">
  String? getVerseFromXml(
      XmlDocument document, String bookName, int chapterNum, int verseNum) {
    // Standardize book name for lookup
    String lookupBookName =
        _bookAbbreviations[bookName.toLowerCase()] ?? bookName;

    // Use root element to avoid full document search
    XmlElement root = document.rootElement;

    // -- Find Book --
    // Try Schema 1: Direct child of root
    var bookElement = root.findElements('BIBLEBOOK').firstWhere(
      (element) {
        final nameAttr = element.getAttribute('bname');
        return nameAttr?.toLowerCase() == lookupBookName.toLowerCase() ||
            nameAttr?.toLowerCase() == bookName.toLowerCase();
      },
      orElse: () => XmlElement(XmlName('notfound')),
    );

    // Try Schema 2 if not found
    if (bookElement.name.local == 'notfound') {
      bookElement = root.findElements('b').firstWhere(
        (element) {
          final nameAttr = element.getAttribute('n');
          return nameAttr?.toLowerCase() == lookupBookName.toLowerCase() ||
              nameAttr?.toLowerCase() == bookName.toLowerCase();
        },
        orElse: () => XmlElement(XmlName('notfound')),
      );
    }

    if (bookElement.name.local == 'notfound') {
      // debugPrint('Book "$bookName" not found in XML.'); // Commented out to reduce log spam
      return null;
    }

    // -- Find Chapter --
    // Try Schema 1: Direct child of book
    var chapterElement = bookElement.findElements('CHAPTER').firstWhere(
          (element) => element.getAttribute('cnumber') == chapterNum.toString(),
          orElse: () => XmlElement(XmlName('notfound')),
        );

    // Try Schema 2 if not found
    if (chapterElement.name.local == 'notfound') {
      chapterElement = bookElement.findElements('c').firstWhere(
            (element) => element.getAttribute('n') == chapterNum.toString(),
            orElse: () => XmlElement(XmlName('notfound')),
          );
    }

    if (chapterElement.name.local == 'notfound') {
      // debugPrint('Chapter "$chapterNum" not found for book "$bookName".');
      return null;
    }

    // -- Find Verse --
    // Try Schema 1: Direct child of chapter
    var verseElement = chapterElement.findElements('VERS').firstWhere(
          (element) => element.getAttribute('vnumber') == verseNum.toString(),
          orElse: () => XmlElement(XmlName('notfound')),
        );

    // Try Schema 2 if not found
    if (verseElement.name.local == 'notfound') {
      verseElement = chapterElement.findElements('v').firstWhere(
            (element) => element.getAttribute('n') == verseNum.toString(),
            orElse: () => XmlElement(XmlName('notfound')),
          );
    }

    if (verseElement.name.local == 'notfound') {
      // debugPrint('Verse "$verseNum" not found for Chapter "$chapterNum", book "$bookName".');
      return null;
    }

    // Extract the text content of the verse
    return verseElement.innerText.trim();
  }

  /// Retrieves a specific verse from an XML asset file.
  Future<String?> getVerseFromAsset(String assetPath, String reference) async {
    final parsedRef = parseReference(reference);
    if (parsedRef == null) {
      debugPrint('Invalid reference format: $reference');
      return null;
    }

    final document = await loadXmlAsset(assetPath);
    final bookName = parsedRef['book']!;
    final chapterNum = int.parse(parsedRef['chapter']!);
    final verseNum = int.parse(parsedRef['verse']!);

    return getVerseFromXml(document, bookName, chapterNum, verseNum);
  }
}
