import 'dart:math';

import 'package:flutter/foundation.dart';

class HealthCalcualtorViewModel extends ChangeNotifier {
  // BMI
  double? bmiResult;
  String? bmiCategory;

  // BMR / Calories
  double? bmrResult;
  double? caloriesResult;
  String? bmrRange;
  String? calorieRange;

  // IBW
  double? ibwResult;
  double? weightDifference;
  String? weightStatus;

  // Body Fat
  double? bodyFatResult;
  String? bodyFatCategory;

  // Crabs/Protein/Fat
  double? carbsCalories;
  double? proteinCalories;
  double? fatCalories;
  double? carbsGrams;
  double? proteinGrams;
  double? fatGrams;
  String? dietType;

  // Ovulation
  Map<String, dynamic>? ovulationResult;

  // Delivery
  Map<String, dynamic>? deliveryResult;

  Map<String, dynamic>? bloodSugarResult;
  Map<String, dynamic>? bloodCholesterolResult;
  Map<String, dynamic>? triglyceridesResult;

  String? _mgdlValue;

  String? get mgdlValue => _mgdlValue;

  String? _mmolValue;

  String? get mmolValue => _mmolValue;

  // Store the original entered value and which field it was entered in
  String? _originalValue;
  String _originalUnit = 'mg/dL'; // which field the original value was entered in
  bool _isSwapped = false; // toggle state for switch

  String _activeUnit = 'mg/dL'; // current source unit
  String get activeUnit => _activeUnit;

  // ================== BLOOD CHOLESTEROL ==================
  String? _cholMgdlValue;
  String? _cholMmolValue;
  String? _cholOriginalValue;
  String _cholOriginalUnit = 'mg/dL';
  bool _cholIsSwapped = false;
  String _cholActiveUnit = 'mg/dL';

  String? get cholMgdlValue => _cholMgdlValue;

  String? get cholMmolValue => _cholMmolValue;

  String get cholActiveUnit => _cholActiveUnit;

  // ================== TRIGLYCERIDES ==================
  String? _triMgdlValue;
  String? _triMmolValue;
  String? _triOriginalValue;
  String _triOriginalUnit = 'mg/dL';
  bool _triIsSwapped = false;
  String _triActiveUnit = 'mg/dL';

  String? get triMgdlValue => _triMgdlValue;

  String? get triMmolValue => _triMmolValue;

  String get triActiveUnit => _triActiveUnit;

  // Generic helpers

  void calculateBMI({required String heightText, required String weightText, required String heightUnit, required String weightUnit}) {
    if (heightText.trim().isEmpty || weightText.trim().isEmpty) {
      bmiResult = null;
      bmiCategory = null;
      notifyListeners();
      return;
    }

    try {
      double height = double.parse(heightText.trim());
      double weight = double.parse(weightText.trim());

      double heightInMeters = _convertHeightToMeters(height, heightUnit);
      double weightInKg = _convertWeightToKg(weight, weightUnit);

      if (heightInMeters <= 0 || weightInKg <= 0) {
        bmiResult = null;
        bmiCategory = null;
        notifyListeners();
        return;
      }

      double bmi = weightInKg / (heightInMeters * heightInMeters);
      String category = _getBMICategory(bmi);

      bmiResult = bmi;
      bmiCategory = category;
      notifyListeners();
    } catch (e) {
      bmiResult = null;
      bmiCategory = null;
      notifyListeners();
    }
  }

  double _convertHeightToMeters(double height, String unit) {
    switch (unit) {
      case 'cm':
        return height / 100;
      case 'm':
        return height;
      case 'ft':
        return height * 0.3048;
      case 'in':
        return height * 0.0254;
      default:
        return height / 100;
    }
  }

  double _convertWeightToKg(double weight, String unit) {
    switch (unit) {
      case 'kg':
        return weight;
      case 'lb':
        return weight * 0.453592;
      default:
        return weight;
    }
  }

  String _getBMICategory(double bmi) {
    if (bmi < 18.5) {
      return 'Underweight';
    } else if (bmi >= 18.5 && bmi < 25) {
      return 'Normal';
    } else if (bmi >= 25 && bmi < 30) {
      return 'Overweight';
    } else {
      return 'Obese';
    }
  }

  // BMR / Calories (shared logic)
  void calculateBMRAndCalories(
      {required String heightText,
      required String weightText,
      required String ageText,
      required String heightUnit,
      required String weightUnit,
      required String gender,
      required String activityLevel,
      bool forCaloriesOnly = false}) {
    if (heightText.trim().isEmpty || weightText.trim().isEmpty || ageText.trim().isEmpty) {
      bmrResult = null;
      caloriesResult = null;
      bmrRange = null;
      calorieRange = null;
      notifyListeners();
      return;
    }

    try {
      double height = double.parse(heightText.trim());
      double weight = double.parse(weightText.trim());
      int age = int.parse(ageText.trim());

      if (age < 11 || age > 120) {
        bmrResult = null;
        caloriesResult = null;
        bmrRange = null;
        calorieRange = null;
        notifyListeners();
        return;
      }

      double heightInCm = _convertHeightToCm(height, heightUnit);
      double weightInKg = _convertWeightToKg(weight, weightUnit);

      if (heightInCm <= 0 || weightInKg <= 0) {
        bmrResult = null;
        caloriesResult = null;
        bmrRange = null;
        calorieRange = null;
        notifyListeners();
        return;
      }

      double bmr = _calculateBMR(heightInCm, weightInKg, age, gender);
      double activityMultiplier = _getActivityMultiplier(activityLevel);
      double calories = bmr * activityMultiplier;

      bmrResult = bmr;
      caloriesResult = calories;

      // ranges
      if (bmr < 1200) {
        bmrRange = 'Low';
      } else if (bmr < 1600) {
        bmrRange = 'Normal';
      } else if (bmr < 2000) {
        bmrRange = 'High';
      } else {
        bmrRange = 'Very High';
      }

      if (calories < 1800) {
        calorieRange = 'Low';
      } else if (calories < 2500) {
        calorieRange = 'Normal';
      } else if (calories < 3200) {
        calorieRange = 'High';
      } else {
        calorieRange = 'High';
      }

      notifyListeners();
    } catch (e) {
      bmrResult = null;
      caloriesResult = null;
      bmrRange = null;
      calorieRange = null;
      notifyListeners();
    }
  }

  double _convertHeightToCm(double height, String unit) {
    switch (unit) {
      case 'cm':
        return height;
      case 'm':
        return height * 100;
      case 'ft':
        return height * 30.48;
      case 'in':
        return height * 2.54;
      default:
        return height;
    }
  }

  double _calculateBMR(double heightCm, double weightKg, int age, String gender) {
    if (gender == "Male") {
      return 88.362 + (13.397 * weightKg) + (4.799 * heightCm) - (5.677 * age);
    } else {
      return 447.593 + (9.247 * weightKg) + (3.098 * heightCm) - (4.330 * age);
    }
  }

  double _getActivityMultiplier(String activityLevel) {
    switch (activityLevel) {
      case "Almost Inactive (no exercise)":
        return 1.2;
      case "Lightly active":
        return 1.375;
      case "Lightly active (1-3) days per week":
        return 1.55;
      case "Super active (very hard exercise)":
        return 1.725;
      default:
        return 1.375;
    }
  }

  // IBW
  void calculateIBW(
      {required String heightText,
      required String weightText,
      required String heightUnit,
      required String weightUnit,
      required String bodyFrameSize}) {
    if (heightText.trim().isEmpty || weightText.trim().isEmpty) {
      ibwResult = null;
      weightDifference = null;
      weightStatus = null;
      notifyListeners();
      return;
    }

    try {
      double height = double.parse(heightText.trim());
      double weight = double.parse(weightText.trim());

      double heightInCm = _convertHeightToCm(height, heightUnit);
      double weightInKg = _convertWeightToKg(weight, weightUnit);

      if (heightInCm <= 0 || weightInKg <= 0) {
        ibwResult = null;
        weightDifference = null;
        weightStatus = null;
        notifyListeners();
        return;
      }

      double ibw = _calculateIBWValue(heightInCm);
      double adjusted = _applyFrameSizeAdjustment(ibw, bodyFrameSize);
      double difference = weightInKg - adjusted;
      String status = _getWeightStatus(difference);

      ibwResult = adjusted;
      weightDifference = difference;
      weightStatus = status;
      notifyListeners();
    } catch (e) {
      ibwResult = null;
      weightDifference = null;
      weightStatus = null;
      notifyListeners();
    }
  }

  double _calculateIBWValue(double heightCm) {
    double baseHeight = 152.4;
    double baseWeight = 50.0;
    double heightMultiplier = 2.3;

    if (heightCm <= baseHeight) {
      return baseWeight - ((baseHeight - heightCm) * 0.5);
    }

    return baseWeight + ((heightCm - baseHeight) * heightMultiplier / 2.54);
  }

  double _applyFrameSizeAdjustment(double ibw, String selectedBodyFrameSize) {
    switch (selectedBodyFrameSize) {
      case "Small (fingers overlaps)":
        return ibw * 0.9;
      case "Medium (fingers touch)":
        return ibw;
      case "Large (fingers don't touch)":
        return ibw * 1.1;
      default:
        return ibw;
    }
  }

  String _getWeightStatus(double difference) {
    if (difference.abs() < 2) {
      return 'Normal';
    } else if (difference > 0) {
      return 'Overweight';
    } else {
      return 'Underweight';
    }
  }

  // Body Fat
  void calculateBodyFat(
      {required String heightText,
      required String neckText,
      required String waistText,
      required String hipText,
      required String heightUnit,
      required String neckUnit,
      required String waistUnit,
      required String hipUnit,
      required String gender}) {
    if (heightText.trim().isEmpty || neckText.trim().isEmpty || waistText.trim().isEmpty) {
      bodyFatResult = null;
      bodyFatCategory = null;
      notifyListeners();
      return;
    }

    if (gender == "Female" && hipText.trim().isEmpty) {
      bodyFatResult = null;
      bodyFatCategory = null;
      notifyListeners();
      return;
    }

    try {
      double height = double.parse(heightText.trim());
      double neck = double.parse(neckText.trim());
      double waist = double.parse(waistText.trim());
      double hip = gender == "Female" ? double.parse(hipText.trim()) : 0;

      double heightInCm = _convertHeightToCm(height, heightUnit);
      double neckInCm = _convertLengthToCm(neck, neckUnit);
      double waistInCm = _convertLengthToCm(waist, waistUnit);
      double hipInCm = gender == "Female" ? _convertLengthToCm(hip, hipUnit) : 0;

      if (heightInCm <= 0 || neckInCm <= 0 || waistInCm <= 0) {
        bodyFatResult = null;
        bodyFatCategory = null;
        notifyListeners();
        return;
      }

      double bodyFat = _calculateBodyFatPercentage(heightInCm, neckInCm, waistInCm, hipInCm, gender == "Male");
      String category = _getBodyFatCategory(bodyFat, gender == "Male");

      bodyFatResult = bodyFat;
      bodyFatCategory = category;
      notifyListeners();
    } catch (e) {
    } catch (e) {
      bodyFatResult = null;
      bodyFatCategory = null;
      notifyListeners();
    }
  }

  double _convertLengthToCm(double length, String unit) {
    switch (unit) {
      case 'cm':
        return length;
      case 'm':
        return length * 100;
      case 'ft':
        return length * 30.48;
      case 'in':
        return length * 2.54;
      default:
        return length;
    }
  }

  double _calculateBodyFatPercentage(double heightCm, double neckCm, double waistCm, double hipCm, bool isMale) {
    if (isMale) {
      double waistMinusNeck = waistCm - neckCm;
      if (waistMinusNeck <= 0) return 0;
      double log10WaistNeck = _log10(waistMinusNeck);
      double log10Height = _log10(heightCm);
      double bodyDensity = 1.0324 - (0.19077 * log10WaistNeck) + (0.15456 * log10Height);
      double bodyFat = (495 / bodyDensity) - 450;
      return bodyFat.clamp(0, 100);
    } else {
      double waistHipMinusNeck = waistCm + hipCm - neckCm;
      if (waistHipMinusNeck <= 0) return 0;
      double log10WaistHipNeck = _log10(waistHipMinusNeck);
      double log10Height = _log10(heightCm);
      double bodyDensity = 1.29579 - (0.35004 * log10WaistHipNeck) + (0.22100 * log10Height);
      double bodyFat = (495 / bodyDensity) - 450;
      return bodyFat.clamp(0, 100);
    }
  }

  double _log10(double x) {
    return (x <= 0) ? 0 : (log(x) / log(10));
  }

  String _getBodyFatCategory(double bodyFat, bool isMale) {
    if (isMale) {
      if (bodyFat < 6) return 'Essential Fat';
      if (bodyFat < 14) return 'Athletes';
      if (bodyFat < 18) return 'Fitness';
      if (bodyFat < 25) return 'Average';
      return 'Obese';
    } else {
      if (bodyFat < 14) return 'Essential Fat';
      if (bodyFat < 21) return 'Athletes';
      if (bodyFat < 25) return 'Fitness';
      if (bodyFat < 32) return 'Average';
      return 'Obese';
    }
  }

  // Crabs / Macros
  void calculateMacros({required String caloriesText, required String selectedDietType}) {
    if (caloriesText.trim().isEmpty) {
      carbsCalories = null;
      proteinCalories = null;
      fatCalories = null;
      carbsGrams = null;
      proteinGrams = null;
      fatGrams = null;
      dietType = null;
      notifyListeners();
      return;
    }

    try {
      double totalCalories = double.parse(caloriesText.trim());
      if (totalCalories <= 0) {
        carbsCalories = null;
        proteinCalories = null;
        fatCalories = null;
        carbsGrams = null;
        proteinGrams = null;
        fatGrams = null;
        dietType = null;
        notifyListeners();
        return;
      }

      Map<String, double> macroPercentages = _getMacroPercentages(selectedDietType);
      double carbsPercent = macroPercentages['carbs']!;
      double proteinPercent = macroPercentages['protein']!;
      double fatPercent = macroPercentages['fat']!;

      double cCalories = totalCalories * (carbsPercent / 100);
      double pCalories = totalCalories * (proteinPercent / 100);
      double fCalories = totalCalories * (fatPercent / 100);

      double cGrams = cCalories / 4;
      double pGrams = pCalories / 4;
      double fGrams = fCalories / 9;

      carbsCalories = cCalories;
      proteinCalories = pCalories;
      fatCalories = fCalories;
      carbsGrams = cGrams;
      proteinGrams = pGrams;
      fatGrams = fGrams;
      dietType = selectedDietType;
      notifyListeners();
    } catch (e) {
      carbsCalories = null;
      proteinCalories = null;
      fatCalories = null;
      carbsGrams = null;
      proteinGrams = null;
      fatGrams = null;
      dietType = null;
      notifyListeners();
    }
  }

  Map<String, double> _getMacroPercentages(String dietType) {
    switch (dietType) {
      case "Very Low Crabs":
        return {'carbs': 5, 'protein': 30, 'fat': 65};
      case "Low Crabs":
        return {'carbs': 20, 'protein': 35, 'fat': 45};
      case "Moderate Crabs":
        return {'carbs': 40, 'protein': 30, 'fat': 30};
      case "USDA Guidelines ":
        return {'carbs': 55, 'protein': 15, 'fat': 30};
      case "Zone Diet":
        return {'carbs': 40, 'protein': 30, 'fat': 30};
      default:
        return {'carbs': 40, 'protein': 30, 'fat': 30};
    }
  }

  // Ovulation
  DateTime? _parseCustomDate(String dateString) {
    try {
      List<String> parts = dateString.split(' ');
      if (parts.length >= 3) {
        int day = int.parse(parts[0]);
        String month = parts[1].replaceAll(',', '');
        int year = int.parse(parts[2]);

        Map<String, int> months = {
          'January': 1,
          'February': 2,
          'March': 3,
          'April': 4,
          'May': 5,
          'June': 6,
          'July': 7,
          'August': 8,
          'September': 9,
          'October': 10,
          'November': 11,
          'December': 12,
          'Jan': 1,
          'Feb': 2,
          'Mar': 3,
          'Apr': 4,
          'Jun': 6,
          'Jul': 7,
          'Aug': 8,
          'Sep': 9,
          'Oct': 10,
          'Nov': 11,
          'Dec': 12,
        };

        int? monthNum = months[month];
        if (monthNum != null) {
          return DateTime(year, monthNum, day);
        }
      }
      return null;
    } catch (e) {
      return null;
    }
  }

  DateTime? _tryParseDate(String dateString) {
    try {
      // try ISO like
      return DateTime.tryParse(dateString) ?? _parseCustomDate(dateString);
    } catch (e) {
      return null;
    }
  }

  String _formatDate(DateTime? date) {
    if (date == null) return '';
    String day = date.day.toString().padLeft(2, '0');
    return '$day ${_getMonthName(date.month)}, ${date.year}';
  }

  String _getMonthName(int month) {
    const List<String> months = [
      'January',
      'February',
      'March',
      'April',
      'May',
      'June',
      'July',
      'August',
      'September',
      'October',
      'November',
      'December'
    ];
    return months[month - 1];
  }

  String _getDayName(int weekday) {
    // DateTime.weekday returns 1 for Monday and 7 for Sunday.
    const List<String> days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
    return days[weekday - 1];
  }

  String _formatDateWithDayName(DateTime? date) {
    if (date == null) return '';
    String dayName = _getDayName(date.weekday); // Gets 'Monday', 'Tuesday', etc.
    return dayName;
  }

  Map<String, double> convertBloodSugar(double value, String fromUnit) {
    if (fromUnit == 'mg/dL') {
      final mmolL = value / 18.0182;
      return {'mgdL': value, 'mmolL': mmolL};
    } else if (fromUnit == 'mmol/L') {
      final mgdL = value * 18.0182;
      return {'mgdL': mgdL, 'mmolL': value};
    }
    return {'mgdL': 0, 'mmolL': 0};
  }

  String _determineCyclePhase(int daysSincePeriod, int follicularPhase, int cycleLength) {
    int normalizedDay = daysSincePeriod % cycleLength;

    if (normalizedDay < follicularPhase - 1) {
      return 'Follicular Phase';
    } else if (normalizedDay < follicularPhase + 2) {
      return 'Ovulation';
    } else if (normalizedDay < cycleLength) {
      return 'Luteal Phase';
    } else {
      return 'Menstruation';
    }
  }

  void calculateOvulation({required String dateText, required String cycleLengthText, required String lutealPhaseText}) {
    if (dateText.trim().isEmpty || cycleLengthText.trim().isEmpty || lutealPhaseText.trim().isEmpty) {
      ovulationResult = null;
      notifyListeners();
      return;
    }

    DateTime? parsedDate = _tryParseDate(dateText);
    if (parsedDate == null) {
      ovulationResult = null;
      notifyListeners();
      return;
    }

    try {
      int cycleLength = int.parse(cycleLengthText.trim());
      int lutealPhase = int.parse(lutealPhaseText.trim());

      if (cycleLength < 16 || cycleLength > 40 || lutealPhase < 8 || lutealPhase > 16) {
        ovulationResult = null;
        notifyListeners();
        return;
      }

      if (cycleLength <= lutealPhase) {
        ovulationResult = null;
        notifyListeners();
        return;
      }

      int follicularPhase = cycleLength - lutealPhase;
      DateTime ovulationDate = parsedDate.add(Duration(days: follicularPhase - 1));
      DateTime fertileStart = ovulationDate.subtract(Duration(days: 5));
      DateTime fertileEnd = ovulationDate.add(Duration(days: 1));
      int daysSincePeriod = DateTime.now().difference(parsedDate).inDays;
      String cyclePhase = _determineCyclePhase(daysSincePeriod, follicularPhase, cycleLength);

      ovulationResult = {
        'lastPeriodDay': _formatDateWithDayName(parsedDate),
        'ovulationDay': _formatDateWithDayName(ovulationDate),
        'lastPeriodDate': _formatDate(parsedDate),
        'ovulationDate': _formatDate(ovulationDate),
        'fertileWindowStart': _formatDate(fertileStart),
        'fertileWindowEnd': _formatDate(fertileEnd),
        'cycleLength': cycleLength,
        'lutealPhase': lutealPhase,
        'follicularPhase': follicularPhase,
        'cyclePhase': cyclePhase,
        'nextPeriodDate': _formatDate(parsedDate.add(Duration(days: cycleLength))),
      };

      notifyListeners();
    } catch (e) {
      ovulationResult = null;
      notifyListeners();
    }
  }

  // Delivery due date
  void calculateDueDate({required String isoDateString}) {
    if (isoDateString.trim().isEmpty) {
      deliveryResult = null;
      notifyListeners();
      return;
    }

    DateTime? lmp;
    try {
      lmp = DateTime.tryParse(isoDateString) ?? _tryParseDate(isoDateString);
    } catch (_) {
      lmp = null;
    }

    if (lmp == null) {
      deliveryResult = null;
      notifyListeners();
      return;
    }

    // Pregnancy constants
    const int totalPregnancyDays = 280;

    // Calculate main dates
    final DateTime dueDate = lmp.add(const Duration(days: totalPregnancyDays));

    // Trimester calculations
    final DateTime firstTrimesterStart = lmp;
    final DateTime firstTrimesterEnd = lmp.add(const Duration(days: 83));

    final DateTime secondTrimesterStart = firstTrimesterEnd.add(const Duration(days: 1));
    final DateTime secondTrimesterEnd = lmp.add(const Duration(days: 195));

    final DateTime thirdTrimesterStart = secondTrimesterEnd.add(const Duration(days: 1));
    final DateTime thirdTrimesterEnd = dueDate;

    deliveryResult = {
      'lmpDate': _formatDate(lmp),
      'dueDate': _formatDate(dueDate),
      // Raw DateTime (useful for logic/UI)
      'lmpDateTime': lmp,
      'dueDateTime': dueDate,
      'dueDateDay': _formatDateWithDayName(dueDate),
      // Trimester info
      'firstTrimester': {
        'start': _formatDate(firstTrimesterStart),
        'end': _formatDate(firstTrimesterEnd),
        'weeks': '1–12',
        'startDateTime': firstTrimesterStart,
        'endDateTime': firstTrimesterEnd,
      },
      'secondTrimester': {
        'start': _formatDate(secondTrimesterStart),
        'end': _formatDate(secondTrimesterEnd),
        'weeks': '13–27',
        'startDateTime': secondTrimesterStart,
        'endDateTime': secondTrimesterEnd,
      },
      'thirdTrimester': {
        'start': _formatDate(thirdTrimesterStart),
        'end': _formatDate(thirdTrimesterEnd),
        'weeks': '28–40',
        'startDateTime': thirdTrimesterStart,
        'endDateTime': thirdTrimesterEnd,
      },
    };

    notifyListeners();
  }

  // Blood sugar conversions
  void calculateBloodSugar({required String valueText, required String unit}) {
    if (valueText.trim().isEmpty) {
      bloodSugarResult = null;
      notifyListeners();
      return;
    }

    try {
      double value = double.parse(valueText.trim());

      if (value <= 0) {
        bloodSugarResult = null;
        notifyListeners();
        return;
      }

      double converted;
      String convertedUnit;

      if (unit == 'mg/dL' || unit == 'MG/DL' || unit.toLowerCase().contains('mg')) {
        // mg/dL -> mmol/L (glucose): divide by 18.0182
        converted = value / 18.0182;
        convertedUnit = 'mmol/L';
      } else {
        // mmol/L -> mg/dL
        converted = value * 18.0182;
        convertedUnit = 'mg/dL';
      }

      // round to sensible precision
      double convertedRounded = double.parse(converted.toStringAsFixed(2));

      bloodSugarResult = {
        'input': value,
        'inputUnit': unit,
        'converted': convertedRounded,
        'convertedUnit': convertedUnit,
      };
      notifyListeners();
    } catch (e) {
      bloodSugarResult = null;
      notifyListeners();
    }
  }

  // expose map-like results for widgets to forward to parent
  Map<String, dynamic>? get bmiResultMap => bmiResult == null ? null : {'bmiResult': bmiResult, 'bmiCategory': bmiCategory};

  Map<String, dynamic>? get caloriesResultMap =>
      caloriesResult == null ? null : {'calories': caloriesResult, 'bmr': bmrResult, 'calorieRange': calorieRange, 'bmrRange': bmrRange};

  Map<String, dynamic>? get ibwResultMap => ibwResult == null ? null : {'ibw': ibwResult, 'difference': weightDifference, 'status': weightStatus};

  Map<String, dynamic>? get bodyFatResultMap => bodyFatResult == null ? null : {'fatPercentage': bodyFatResult, 'fatCategory': bodyFatCategory};

  Map<String, dynamic>? get macrosResultMap => carbsCalories == null
      ? null
      : {
          'totalCalories': carbsCalories! + proteinCalories! + fatCalories!,
          'carbsGrams': carbsGrams,
          'carbsCalories': carbsCalories,
          'proteinGrams': proteinGrams,
          'proteinCalories': proteinCalories,
          'fatGrams': fatGrams,
          'fatCalories': fatCalories,
          'dietType': dietType
        };

  void onBloodSugarChanged(String value, String fromUnit) {
    _activeUnit = fromUnit;

    if (value.isEmpty) {
      _mgdlValue = null;
      _mmolValue = null;
      notifyListeners();
      return;
    }

    final parsed = double.tryParse(value);
    if (parsed == null) return;

    if (fromUnit == 'mg/dL') {
      _mgdlValue = value;
      _mmolValue = (parsed / 18.0182).toStringAsFixed(3);
    } else {
      _mmolValue = value;
      _mgdlValue = (parsed * 18.0182).toStringAsFixed(3);
    }

    notifyListeners();
  }

  void onBloodSugarMgdlChanged(String value) {
    _mgdlValue = value;
    _originalValue = value;
    _originalUnit = 'mg/dL';
    _isSwapped = false;
    _activeUnit = 'mg/dL';

    if (value.isEmpty) {
      _mmolValue = null;
      _originalValue = null;
      notifyListeners();
      return;
    }

    final parsed = double.tryParse(value);
    if (parsed == null) return;

    // Convert mg/dL to mmol/L
    _mmolValue = (parsed / 18.0182).toStringAsFixed(3);
    notifyListeners();
  }

  void onBloodSugarMmolChanged(String value) {
    _mmolValue = value;
    _originalValue = value;
    _originalUnit = 'mmol/L';
    _isSwapped = false;
    _activeUnit = 'mmol/L';

    if (value.isEmpty) {
      _mgdlValue = null;
      _originalValue = null;
      notifyListeners();
      return;
    }

    final parsed = double.tryParse(value);
    if (parsed == null) return;

    // Convert mmol/L to mg/dL
    _mgdlValue = (parsed * 18.0182).toStringAsFixed(3);
    notifyListeners();
  }

  void switchBloodSugarValues() {
    // Toggle between two states using the original entered value
    if (_originalValue == null || _originalValue!.isEmpty) return;

    final originalParsed = double.tryParse(_originalValue!);
    if (originalParsed == null) return;

    _isSwapped = !_isSwapped;

    if (_originalUnit == 'mg/dL') {
      if (_isSwapped) {
        // Original was in mg/dL, now treat it as mmol/L
        _mmolValue = _originalValue; // Keep original format
        _mgdlValue = (originalParsed * 18.0182).toStringAsFixed(3);
      } else {
        // Back to original: value in mg/dL
        _mgdlValue = _originalValue; // Keep original format
        _mmolValue = (originalParsed / 18.0182).toStringAsFixed(3);
      }
    } else {
      // Original was in mmol/L
      if (_isSwapped) {
        // Now treat it as mg/dL
        _mgdlValue = _originalValue; // Keep original format
        _mmolValue = (originalParsed / 18.0182).toStringAsFixed(3);
      } else {
        // Back to original: value in mmol/L
        _mmolValue = _originalValue; // Keep original format
        _mgdlValue = (originalParsed * 18.0182).toStringAsFixed(3);
      }
    }

    notifyListeners();
  }

  // --- NEW: Method to clear the values ---
  void clearBloodSugar() {
    _mgdlValue = null;
    _mmolValue = null;
    _originalValue = null;
    _originalUnit = 'mg/dL';
    _isSwapped = false;
    _activeUnit = 'mg/dL';
    notifyListeners();
  }

  void onBloodCholesterolChanged(String value, String fromUnit) {
    _cholActiveUnit = fromUnit;

    if (value.isEmpty) {
      _cholMgdlValue = null;
      _cholMmolValue = null;
      notifyListeners();
      return;
    }

    final parsed = double.tryParse(value);
    if (parsed == null) return;

    if (fromUnit == 'mg/dL') {
      _cholMgdlValue = value;
      _cholMmolValue = (parsed / 38.67).toStringAsFixed(3);
    } else {
      _cholMmolValue = value;
      _cholMgdlValue = (parsed * 38.67).toStringAsFixed(3);
    }

    notifyListeners();
  }

  void onCholesterolMgdlChanged(String value) {
    _cholMgdlValue = value;
    _cholOriginalValue = value;
    _cholOriginalUnit = 'mg/dL';
    _cholIsSwapped = false;
    _cholActiveUnit = 'mg/dL';

    if (value.isEmpty) {
      _cholMmolValue = null;
      _cholOriginalValue = null;
      notifyListeners();
      return;
    }

    final parsed = double.tryParse(value);
    if (parsed == null) return;

    // Convert mg/dL to mmol/L
    _cholMmolValue = (parsed / 38.67).toStringAsFixed(3);
    notifyListeners();
  }

  void onCholesterolMmolChanged(String value) {
    _cholMmolValue = value;
    _cholOriginalValue = value;
    _cholOriginalUnit = 'mmol/L';
    _cholIsSwapped = false;
    _cholActiveUnit = 'mmol/L';

    if (value.isEmpty) {
      _cholMgdlValue = null;
      _cholOriginalValue = null;
      notifyListeners();
      return;
    }

    final parsed = double.tryParse(value);
    if (parsed == null) return;

    // Convert mmol/L to mg/dL
    _cholMgdlValue = (parsed * 38.67).toStringAsFixed(3);
    notifyListeners();
  }

  void switchBloodCholesterolValues() {
    // Toggle between two states using the original entered value
    if (_cholOriginalValue == null || _cholOriginalValue!.isEmpty) return;

    final originalParsed = double.tryParse(_cholOriginalValue!);
    if (originalParsed == null) return;

    _cholIsSwapped = !_cholIsSwapped;

    if (_cholOriginalUnit == 'mg/dL') {
      if (_cholIsSwapped) {
        // Original was in mg/dL, now treat it as mmol/L
        _cholMmolValue = _cholOriginalValue; // Keep original format
        _cholMgdlValue = (originalParsed * 38.67).toStringAsFixed(3);
      } else {
        // Back to original: value in mg/dL
        _cholMgdlValue = _cholOriginalValue; // Keep original format
        _cholMmolValue = (originalParsed / 38.67).toStringAsFixed(3);
      }
    } else {
      // Original was in mmol/L
      if (_cholIsSwapped) {
        // Now treat it as mg/dL
        _cholMgdlValue = _cholOriginalValue; // Keep original format
        _cholMmolValue = (originalParsed / 38.67).toStringAsFixed(3);
      } else {
        // Back to original: value in mmol/L
        _cholMmolValue = _cholOriginalValue; // Keep original format
        _cholMgdlValue = (originalParsed * 38.67).toStringAsFixed(3);
      }
    }

    notifyListeners();
  }

  void clearBloodCholesterol() {
    _cholMgdlValue = null;
    _cholMmolValue = null;
    _cholOriginalValue = null;
    _cholOriginalUnit = 'mg/dL';
    _cholIsSwapped = false;
    _cholActiveUnit = 'mg/dL';
    notifyListeners();
  }

  void onTriglyceridesChanged(String value, String fromUnit) {
    _triActiveUnit = fromUnit;

    if (value.isEmpty) {
      _triMgdlValue = null;
      _triMmolValue = null;
      notifyListeners();
      return;
    }

    final parsed = double.tryParse(value);
    if (parsed == null) return;

    if (fromUnit == 'mg/dL') {
      _triMgdlValue = value;
      _triMmolValue = (parsed / 88.57).toStringAsFixed(3);
    } else {
      _triMmolValue = value;
      _triMgdlValue = (parsed * 88.57).toStringAsFixed(3);
    }

    notifyListeners();
  }

  void onTriglyceridesMgdlChanged(String value) {
    _triMgdlValue = value;
    _triOriginalValue = value;
    _triOriginalUnit = 'mg/dL';
    _triIsSwapped = false;
    _triActiveUnit = 'mg/dL';

    if (value.isEmpty) {
      _triMmolValue = null;
      _triOriginalValue = null;
      notifyListeners();
      return;
    }

    final parsed = double.tryParse(value);
    if (parsed == null) return;

    // Convert mg/dL to mmol/L
    _triMmolValue = (parsed / 88.57).toStringAsFixed(3);
    notifyListeners();
  }

  void onTriglyceridesMmolChanged(String value) {
    _triMmolValue = value;
    _triOriginalValue = value;
    _triOriginalUnit = 'mmol/L';
    _triIsSwapped = false;
    _triActiveUnit = 'mmol/L';

    if (value.isEmpty) {
      _triMgdlValue = null;
      _triOriginalValue = null;
      notifyListeners();
      return;
    }

    final parsed = double.tryParse(value);
    if (parsed == null) return;

    // Convert mmol/L to mg/dL
    _triMgdlValue = (parsed * 88.57).toStringAsFixed(3);
    notifyListeners();
  }

  void switchTriglyceridesValues() {
    // Toggle between two states using the original entered value
    if (_triOriginalValue == null || _triOriginalValue!.isEmpty) return;

    final originalParsed = double.tryParse(_triOriginalValue!);
    if (originalParsed == null) return;

    _triIsSwapped = !_triIsSwapped;

    if (_triOriginalUnit == 'mg/dL') {
      if (_triIsSwapped) {
        // Original was in mg/dL, now treat it as mmol/L
        _triMmolValue = _triOriginalValue; // Keep original format
        _triMgdlValue = (originalParsed * 88.57).toStringAsFixed(3);
      } else {
        // Back to original: value in mg/dL
        _triMgdlValue = _triOriginalValue; // Keep original format
        _triMmolValue = (originalParsed / 88.57).toStringAsFixed(3);
      }
    } else {
      // Original was in mmol/L
      if (_triIsSwapped) {
        // Now treat it as mg/dL
        _triMgdlValue = _triOriginalValue; // Keep original format
        _triMmolValue = (originalParsed / 88.57).toStringAsFixed(3);
      } else {
        // Back to original: value in mmol/L
        _triMmolValue = _triOriginalValue; // Keep original format
        _triMgdlValue = (originalParsed * 88.57).toStringAsFixed(3);
      }
    }

    notifyListeners();
  }

  void clearTriglycerides() {
    _triMgdlValue = null;
    _triMmolValue = null;
    _triOriginalValue = null;
    _triOriginalUnit = 'mg/dL';
    _triIsSwapped = false;
    _triActiveUnit = 'mg/dL';
    notifyListeners();
  }
}
