import 'dart:convert';
import 'dart:math';
import 'package:flutter/services.dart';
import 'package:flutter/foundation.dart'; // For debugPrint
import 'package:hive_flutter/hive_flutter.dart'; // Import Hive
import '../services/bible_xml_parser.dart'; // Import the XML parser

import 'cycle_entry.dart';
import 'user_profile.dart';

part 'scripture.g.dart'; // Hive generated adapter

/// Scripture model for daily verses and devotionals
@HiveType(typeId: 10) // Unique typeId for Scripture
class Scripture extends HiveObject {
  @HiveField(0, defaultValue: {})
  final Map<BibleTranslation, String> verses;
  @HiveField(1)
  final String reference;
  @HiveField(2)
  final String? reflection;
  @HiveField(3, defaultValue: [])
  final List<String> applicablePhases;
  @HiveField(4, defaultValue: [])
  final List<String> applicableContexts;

  Scripture({
    required this.verses,
    required this.reference,
    this.reflection,
    this.applicablePhases = const [],
    this.applicableContexts = const [],
  });

  factory Scripture.fromJson(Map<String, dynamic> json) {
    return Scripture(
      verses: (json['verses'] as Map<String, dynamic>).map((key, value) =>
          MapEntry(
              BibleTranslation.values.firstWhere((e) => e.name == key), value)),
      reference: json['reference'],
      reflection: json['reflection'],
      applicablePhases: (json['applicablePhases'] as List<dynamic>?)
              ?.map((e) => e as String)
              .toList() ??
          [],
      applicableContexts: (json['applicableContexts'] as List<dynamic>?)
              ?.map((e) => e as String)
              .toList() ??
          [],
    );
  }

  String getVerse(BibleTranslation translation) {
    return verses[translation] ??
        verses[BibleTranslation.esv] ??
        verses.values.first;
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      (other is Scripture &&
          runtimeType == other.runtimeType &&
          reference == other.reference &&
          reflection == other.reflection &&
          _listEquals(applicablePhases, other.applicablePhases) &&
          _listEquals(applicableContexts, other.applicableContexts) &&
          _mapEquals(verses, other.verses));

  @override
  int get hashCode =>
      reference.hashCode ^
      reflection.hashCode ^
      Object.hashAll(applicablePhases) ^
      Object.hashAll(applicableContexts) ^
      Object.hashAll(verses.entries) ^
      reflection.hashCode;

  // Helper for list equality check
  static bool _listEquals<T>(List<T>? a, List<T>? b) {
    if (a == null) return b == null;
    if (b == null) return false;
    if (a.length != b.length) return false;
    for (int i = 0; i < a.length; i++) {
      if (a[i] != b[i]) return false;
    }
    return true;
  }

  // Helper for map equality check
  static bool _mapEquals<K, V>(Map<K, V>? a, Map<K, V>? b) {
    if (a == null) return b == null;
    if (b == null) return false;
    if (a.length != b.length) return false;
    if (a.keys.length != b.keys.length) return false; // Added length check
    for (final key in a.keys) {
      if (!b.containsKey(key) || a[key] != b[key]) {
        return false; // Added containsKey check
      }
    }
    return true;
  }
}

/// Pre-defined scriptures for the app
class ScriptureDatabase {
  static final ScriptureDatabase _instance = ScriptureDatabase._internal();

  factory ScriptureDatabase({BibleXmlParser? bibleXmlParser}) {
    return _instance;
  }

  ScriptureDatabase._internal();

  late Box<Scripture> _scriptureBox;

  // Mapping of BibleTranslation to its XML asset path

  List<Scripture> _menstrualScriptures = [];
  List<Scripture> _follicularScriptures = [];
  List<Scripture> _ovulationScriptures = [];
  List<Scripture> _lutealScriptures = [];
  List<Scripture> _husbandScriptures = [];
  List<Scripture> _womanhoodScriptures = [];
  Map<String, List<Scripture>> _contextualScriptures = {};

  // Hardcoded scriptures to ensure rich Husband experience immediately
  final List<Scripture> _hardcodedHusbandScriptures = [
    Scripture(
      reference: "Mark 10:45",
      verses: {
        BibleTranslation.esv:
            "For even the Son of Man came not to be served but to serve, and to give his life as a ransom for many.",
        BibleTranslation.niv:
            "For even the Son of Man did not come to be served, but to serve, and to give his life as a ransom for many.",
      },
      reflection:
          "True leadership is servanthood. How can you serve your wife today?",
      applicablePhases: ['husband'],
      applicableContexts: ['leadership', 'servant'],
    ),
    Scripture(
      reference: "Philippians 2:3-4",
      verses: {
        BibleTranslation.esv:
            "Do nothing from selfish ambition or conceit, but in humility count others more significant than yourselves. Let each of you look not only to his own interests, but also to the interests of others.",
      },
      reflection: "Humility is the foundation of a happy marriage.",
      applicablePhases: ['husband'],
      applicableContexts: ['servant', 'humility'],
    ),
    Scripture(
      reference: "Proverbs 29:18",
      verses: {
        BibleTranslation.esv:
            "Where there is no prophetic vision the people cast off restraint, but blessed is he who keeps the law.",
        BibleTranslation.kjv:
            "Where there is no vision, the people perish: but he that keepeth the law, happy is he.",
      },
      reflection: "Lead your family with a clear, Godly vision.",
      applicablePhases: ['husband'],
      applicableContexts: ['vision', 'leadership'],
    ),
    Scripture(
      reference: "James 1:5",
      verses: {
        BibleTranslation.esv:
            "If any of you lacks wisdom, let him ask God, who gives generously to all without reproach, and it will be given him.",
      },
      reflection:
          "Seek God's wisdom in every decision you make for your family.",
      applicablePhases: ['husband'],
      applicableContexts: ['wisdom', 'vision'],
    ),
    Scripture(
      reference: "1 Timothy 3:4-5",
      verses: {
        BibleTranslation.esv:
            "He must manage his own household well, with all dignity keeping his children submissive, for if someone does not know how to manage his own household, how will he care for God's church?",
      },
      reflection:
          "Your first ministry is your home. Manage it with love and dignity.",
      applicablePhases: ['husband'],
      applicableContexts: ['leadership'],
    ),
    Scripture(
      reference: "Colossians 3:19",
      verses: {
        BibleTranslation.esv:
            "Husbands, love your wives, and do not be harsh with them.",
        BibleTranslation.niv:
            "Husbands, love your wives and do not be harsh with them.",
      },
      reflection: "Gentleness is a sign of strength, not weakness.",
      applicablePhases: ['husband'],
      applicableContexts: ['kindness', 'love'],
    ),
    Scripture(
      reference: "1 Corinthians 16:14",
      verses: {
        BibleTranslation.esv: "Let all that you do be done in love.",
      },
      reflection: "Let love be the motivation behind every action and word.",
      applicablePhases: ['husband'],
      applicableContexts: ['love'],
    ),
  ];

  Future<void> loadScriptures() async {
    _scriptureBox = await Hive.openBox<Scripture>('scriptures');

    if (_scriptureBox.isEmpty) {
      debugPrint(
          'Hive box is empty. Importing scriptures from optimized JSON data...');
      // Load the pre-processed JSON file which already contains all verse text
      final String response =
          await rootBundle.loadString('assets/scriptures_optimized.json');
      final Map<String, dynamic> data = json.decode(response);

      List<Scripture> importedScriptures = [];

      // Helper function to process ANY list of scriptures
      void processList(List<dynamic> list, String listName) {
        for (var jsonEntry in list) {
          final reference = jsonEntry['reference'];
          final reflection = jsonEntry['reflection']; // Optional

          final applicablePhases =
              (jsonEntry['applicablePhases'] as List<dynamic>?)
                      ?.map((e) => e as String)
                      .toList() ??
                  [];

          final applicableContexts =
              (jsonEntry['applicableContexts'] as List<dynamic>?)
                      ?.map((e) => e as String)
                      .toList() ??
                  [];

          // Map string keys (esv, niv) to BibleTranslation enum
          Map<BibleTranslation, String> versesMap = {};
          if (jsonEntry['verses'] != null) {
            (jsonEntry['verses'] as Map<String, dynamic>).forEach((key, value) {
              // Find enum by name (case-insensitive usually, but here keys are lowercase 'esv')
              try {
                final translation = BibleTranslation.values.firstWhere(
                    (e) => e.name.toLowerCase() == key.toLowerCase());
                versesMap[translation] = value.toString();
              } catch (e) {
                debugPrint(
                    'Warning: Unknown translation key "$key" in optimized JSON');
              }
            });
          }

          if (versesMap.isNotEmpty) {
            importedScriptures.add(Scripture(
              verses: versesMap,
              reference: reference,
              reflection: reflection,
              applicablePhases: applicablePhases,
              applicableContexts: applicableContexts,
            ));
          }
        }
      }

      // Process all sections
      if (data['menstrual'] != null) {
        processList(data['menstrual'], 'menstrual');
      }
      if (data['follicular'] != null) {
        processList(data['follicular'], 'follicular');
      }
      if (data['ovulation'] != null) {
        processList(data['ovulation'], 'ovulation');
      }
      if (data['luteal'] != null) {
        processList(data['luteal'], 'luteal');
      }
      if (data['husband'] != null) {
        processList(data['husband'], 'husband');
      }
      if (data['womanhood'] != null) {
        processList(data['womanhood'], 'womanhood');
      }

      if (data['contextual'] != null) {
        final contextualMap = data['contextual'] as Map<String, dynamic>;
        contextualMap.forEach((key, value) {
          processList(value as List, 'contextual_$key');
        });
      }

      // Store all imported scriptures into Hive
      final Map<String, Scripture> scripturesMap = {
        for (var s in importedScriptures) s.reference: s
      };
      await _scriptureBox.putAll(scripturesMap);
      debugPrint(
          'Successfully imported ${importedScriptures.length} scriptures.');
    } else {
      debugPrint('Hive box is not empty. Loading scriptures from Hive...');
    }

    // Populate internal lists from Hive box values
    _menstrualScriptures = _scriptureBox.values
        .where((s) => s.applicablePhases.contains('menstrual'))
        .toList();
    _follicularScriptures = _scriptureBox.values
        .where((s) => s.applicablePhases.contains('follicular'))
        .toList();
    _ovulationScriptures = _scriptureBox.values
        .where((s) => s.applicablePhases.contains('ovulation'))
        .toList();
    _lutealScriptures = _scriptureBox.values
        .where((s) => s.applicablePhases.contains('luteal'))
        .toList();
    _husbandScriptures = [
      ..._scriptureBox.values
          .where((s) => s.applicablePhases.contains('husband')),
      ..._hardcodedHusbandScriptures,
    ];
    // Remove duplicates based on reference if any
    final uniqueHusbandIds = <String>{};
    _husbandScriptures = _husbandScriptures.where((s) {
      if (uniqueHusbandIds.contains(s.reference)) return false;
      uniqueHusbandIds.add(s.reference);
      return true;
    }).toList();

    _womanhoodScriptures = _scriptureBox.values
        .where((s) => s.applicableContexts.contains('womanhood'))
        .toList();
    _contextualScriptures = {
      'anxiety': _scriptureBox.values
          .where((s) => s.applicableContexts.contains('anxiety'))
          .toList(),
      'pain': _scriptureBox.values
          .where((s) => s.applicableContexts.contains('pain'))
          .toList(),
      'fatigue': _scriptureBox.values
          .where((s) => s.applicableContexts.contains('fatigue'))
          .toList(),
      'joy': _scriptureBox.values
          .where((s) => s.applicableContexts.contains('joy'))
          .toList(),
    };
  }

  /// Get the number of scriptures for a given phase
  int getScriptureCountForPhase(String phase) {
    switch (phase.toLowerCase()) {
      case 'menstrual':
        return _menstrualScriptures.length;
      case 'follicular':
        return _follicularScriptures.length;
      case 'ovulation':
        return _ovulationScriptures.length;
      case 'luteal':
        return _lutealScriptures.length;
      case 'husband':
        return _husbandScriptures.length;
      case 'womanhood':
        return _womanhoodScriptures.length;
      case 'anxiety':
        return _contextualScriptures['anxiety']?.length ?? 0;
      case 'pain':
        return _contextualScriptures['pain']?.length ?? 0;
      case 'fatigue':
        return _contextualScriptures['fatigue']?.length ?? 0;
      case 'joy':
        return _contextualScriptures['joy']?.length ?? 0;
      default:
        return 0;
    }
  }

  /// Get recommended scripture based on entry
  Scripture? getRecommendedScripture(CycleEntry entry) {
    if (entry.mood == MoodLevel.verySad ||
        entry.mood == MoodLevel.sad ||
        (entry.stressLevel != null && entry.stressLevel! > 3)) {
      final scriptures = _contextualScriptures['anxiety'];
      if (scriptures != null && scriptures.isNotEmpty) {
        return scriptures[DateTime.now().day % scriptures.length];
      }
    }
    if ((entry.crampIntensity != null && entry.crampIntensity! >= 3) ||
        entry.hasHeadache ||
        entry.hasLowerBackPain) {
      final scriptures = _contextualScriptures['pain'];
      if (scriptures != null && scriptures.isNotEmpty) {
        return scriptures[DateTime.now().day % scriptures.length];
      }
    }
    if (entry.hasFatigue ||
        entry.hasInsomnia ||
        (entry.energyLevel != null && entry.energyLevel! <= 2)) {
      final scriptures = _contextualScriptures['fatigue'];
      if (scriptures != null && scriptures.isNotEmpty) {
        return scriptures[DateTime.now().day % scriptures.length];
      }
    }
    if (entry.mood == MoodLevel.veryHappy) {
      final scriptures = _contextualScriptures['joy'];
      if (scriptures != null && scriptures.isNotEmpty) {
        return scriptures[DateTime.now().day % scriptures.length];
      }
    }
    return null;
  }

  /// Get scripture for current phase by index
  Scripture? getScriptureForPhaseByIndex(String phase, int index) {
    List<Scripture> scriptures;
    switch (phase.toLowerCase()) {
      case 'menstrual':
        scriptures = _menstrualScriptures;
        break;
      case 'follicular':
        scriptures = _follicularScriptures;
        break;
      case 'ovulation':
        scriptures = _ovulationScriptures;
        break;
      case 'luteal':
        scriptures = _lutealScriptures;
        break;
      case 'husband':
        scriptures = _husbandScriptures;
        break;
      case 'womanhood':
        scriptures = _womanhoodScriptures;
        break;
      case 'anxiety':
        scriptures = _contextualScriptures['anxiety'] ?? [];
        break;
      case 'pain':
        scriptures = _contextualScriptures['pain'] ?? [];
        break;
      case 'fatigue':
        scriptures = _contextualScriptures['fatigue'] ?? [];
        break;
      case 'joy':
        scriptures = _contextualScriptures['joy'] ?? [];
        break;
      default:
        return null;
    }
    if (scriptures.isEmpty || index < 0 || index >= scriptures.length) {
      return null;
    }
    return scriptures[index];
  }

// ... imports

// ... inside ScriptureDatabase class

  /// Get a random scripture for a given phase
  Scripture? getRandomScriptureForPhase(String phase) {
    List<Scripture> scriptures;
    switch (phase.toLowerCase()) {
      case 'menstrual':
        scriptures = _menstrualScriptures;
        break;
      case 'follicular':
        scriptures = _follicularScriptures;
        break;
      case 'ovulation':
        scriptures = _ovulationScriptures;
        break;
      case 'luteal':
        scriptures = _lutealScriptures;
        break;
      case 'husband':
        scriptures = _husbandScriptures;
        break;
      case 'womanhood':
        scriptures = _womanhoodScriptures;
        break;
      case 'anxiety':
        scriptures = _contextualScriptures['anxiety'] ?? [];
        break;
      case 'pain':
        scriptures = _contextualScriptures['pain'] ?? [];
        break;
      case 'fatigue':
        scriptures = _contextualScriptures['fatigue'] ?? [];
        break;
      case 'joy':
        scriptures = _contextualScriptures['joy'] ?? [];
        break;
      default:
        return null;
    }
    if (scriptures.isEmpty) {
      return null;
    }
    return scriptures[Random().nextInt(scriptures.length)];
  }

  /// Get scripture for current phase (Randomized)
  Scripture getScriptureForPhase(String phase) {
    List<Scripture> scriptures;
    switch (phase.toLowerCase()) {
      // ... (same switch cases)
      case 'menstrual':
        scriptures = _menstrualScriptures;
        break;
      case 'follicular':
        scriptures = _follicularScriptures;
        break;
      case 'ovulation':
        scriptures = _ovulationScriptures;
        break;
      case 'luteal':
        scriptures = _lutealScriptures;
        break;
      case 'husband':
        scriptures = _husbandScriptures;
        break;
      case 'womanhood':
        scriptures = _womanhoodScriptures;
        break;
      case 'anxiety':
        scriptures = _contextualScriptures['anxiety'] ?? [];
        break;
      case 'pain':
        scriptures = _contextualScriptures['pain'] ?? [];
        break;
      case 'fatigue':
        scriptures = _contextualScriptures['fatigue'] ?? [];
        break;
      case 'joy':
        scriptures = _contextualScriptures['joy'] ?? [];
        break;
      default:
        // Fallback
        scriptures = [
          ..._menstrualScriptures,
          ..._follicularScriptures,
          ..._ovulationScriptures,
          ..._lutealScriptures,
          ..._husbandScriptures,
          ..._womanhoodScriptures,
          ...(_contextualScriptures['anxiety'] ?? []),
          ...(_contextualScriptures['pain'] ?? []),
          ...(_contextualScriptures['fatigue'] ?? []),
          ...(_contextualScriptures['joy'] ?? []),
        ];
        if (scriptures.isEmpty) {
          return Scripture(
              verses: {BibleTranslation.esv: "No scripture found."},
              reference: "Unknown",
              applicablePhases: [],
              applicableContexts: []);
        }
    }

    if (scriptures.isEmpty) {
      return Scripture(
          verses: {BibleTranslation.esv: "No scripture found."},
          reference: "Unknown",
          applicablePhases: [],
          applicableContexts: []);
    }
    return scriptures[Random().nextInt(scriptures.length)];
  }

  /// Get scripture for husband (Randomized)
  Scripture getHusbandScripture() {
    final scriptures = _husbandScriptures;
    if (scriptures.isEmpty) {
      return Scripture(
          verses: {BibleTranslation.esv: "No husband scripture found."},
          reference: "Unknown",
          applicablePhases: [],
          applicableContexts: []);
    }
    return scriptures[Random().nextInt(scriptures.length)];
  }

  /// Get all scriptures
  List<Scripture> getAllScriptures() {
    return _scriptureBox.values.toList();
  }
}
