import 'package:flutter/foundation.dart';
import 'package:health/health.dart';
import 'package:hmg_patient_app_new/core/common_models/data_points.dart';
import 'package:hmg_patient_app_new/core/common_models/smart_watch.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/health_service.dart';
import 'package:hmg_patient_app_new/presentation/smartwatches/activity_detail.dart';
import 'package:hmg_patient_app_new/presentation/smartwatches/smart_watches_health_data_screen.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';

import 'health_data_transformations.dart';
import 'model/vitals_data_model.dart';

class HealthProvider with ChangeNotifier {
  final HealthService _healthService = HealthService();
  Map<HealthDataType, List<HealthDataPoint>> healthData = {};
  bool isLoading = false;
  String? error;
  String selectedTimeRange = '7D';
  int selectedTabIndex = 0;

  SmartWatchTypes? selectedWatchType;

  String selectedWatchURL = 'assets/images/png/smartwatches/apple-watch-5.jpg';
  HealthDataTransformation healthDataTransformation = HealthDataTransformation();

  String selectedSection = "";
  Map<String, List<DataPoint>> daily = {};
  Map<String, List<DataPoint>> weekly = {};
  Map<String, List<DataPoint>> monthly = {};
  Map<String, List<DataPoint>> halgyearly = {};
  Map<String, List<DataPoint>> yearly = {};
  Map<String, List<DataPoint>> selectedData = {};
  Durations selectedDuration = Durations.daily;
  VitalsWRTType? vitals;
  double? averageValue;
  String? averageValueString;

  setSelectedWatchType(SmartWatchTypes type, String imageURL) {
    selectedWatchType = type;
    selectedWatchURL = imageURL;
    notifyListeners();
    _healthService.addWatchHelper(type);
  }

  void onTabChanged(int index) {
    selectedTabIndex = index;
    notifyListeners();
  }

  Future<void> fetchHealthData() async {
    isLoading = true;
    error = null;
    notifyListeners();
    healthData.clear();
    try {
      final authorized = await _healthService.requestAuthorization();
      if (!authorized) {
        error = 'Health data access not authorized';
        isLoading = false;
        notifyListeners();
        return;
      }

      final startTime = _getStartDate();
      final endTime = DateTime.now();
      healthData = await _healthService.getAllHealthData(startTime, endTime);
      isLoading = false;
      notifyListeners();
    } catch (e) {
      error = 'Error fetching health data: $e';
      isLoading = false;
      notifyListeners();
    }
  }

  Future<void> refreshMetric(HealthDataType type) async {
    try {
      final startTime = _getStartDate();
      final endTime = DateTime.now();

      final data = await _healthService.getSpecificHealthData(
        type,
        startTime,
        endTime,
      );

      healthData[type] = data;
      notifyListeners();
    } catch (e) {
      debugPrint('Error refreshing metric $type: $e');
    }
  }

  void updateTimeRange(String range) {
    selectedTimeRange = range;
    fetchHealthData();
  }

  DateTime _getStartDate() {
    switch (selectedTimeRange) {
      case '1D':
        return DateTime.now().subtract(const Duration(days: 1));
      case '7D':
        return DateTime.now().subtract(const Duration(days: 7));
      case '1M':
        return DateTime.now().subtract(const Duration(days: 30));
      case '3M':
        return DateTime.now().subtract(const Duration(days: 90));
      case '1Y':
        return DateTime.now().subtract(const Duration(days: 365));
      default:
        return DateTime.now().subtract(const Duration(days: 7));
    }
  }

  void initDevice() async {
    LoaderBottomSheet.showLoader();
    notifyListeners();
    final result = await _healthService.initDevice();
    isLoading = false;
    LoaderBottomSheet.hideLoader();
    if (result.isError) {
      error = 'Error initializing device: ${result.asError}';
    } else {
      LoaderBottomSheet.showLoader();
      await getVitals();
      // LoaderBottomSheet.hideLoader();
      // await Future.delayed(Duration(seconds: 5));
      getIt.get<NavigationService>().pushPage(page: SmartWatchesHealthDataScreen());
    }
    notifyListeners();
  }

  Future<void> getVitals() async {
    final result = await _healthService.getVitals();
    vitals = result;
    LoaderBottomSheet.hideLoader();

    notifyListeners();
  }

  mapValuesForFilters(
    Durations filter,
    String selectedSection,
  ) {
    if (vitals == null) return {};

    switch (filter) {
      case Durations.daily:
        if (daily.isNotEmpty) {
          selectedData = daily;
          break;
        }
        selectedData = daily = healthDataTransformation.transformVitalsToDataPoints(vitals!, Durations.daily.value, selectedSection);
        break;
      case Durations.weekly:
        if (weekly.isNotEmpty) {
          selectedData = weekly;
          break;
        }
        selectedData = weekly = healthDataTransformation.transformVitalsToDataPoints(vitals!, Durations.weekly.value, selectedSection);
        break;
      case Durations.monthly:
        if (monthly.isNotEmpty) {
          selectedData = monthly;
          break;
        }
        selectedData = monthly = healthDataTransformation.transformVitalsToDataPoints(vitals!, Durations.monthly.value, selectedSection);
        break;
      case Durations.halfYearly:
        if (halgyearly.isNotEmpty) {
          selectedData = halgyearly;
          break;
        }
        selectedData = halgyearly = healthDataTransformation.transformVitalsToDataPoints(vitals!, Durations.halfYearly.value, selectedSection);
        break;
      case Durations.yearly:
        if (yearly.isNotEmpty) {
          selectedData = yearly;
          break;
        }
        selectedData = yearly = healthDataTransformation.transformVitalsToDataPoints(vitals!, Durations.yearly.value, selectedSection);
        break;
    }
    notifyListeners();
  }

  void navigateToDetails(String value, {required String sectionName, required String uom}) {
    getIt.get<NavigationService>().pushPage(
            page: ActivityDetails(
          selectedActivity: value,
          sectionName: sectionName,
          uom: uom,
        ));
  }

  void saveSelectedSection(String value) {
    // if(selectedSection == value) return;
    selectedSection = value;
  }

  void deleteDataIfSectionIsDifferent(String value) {
    // if(selectedSection == value){
    //   return;
    // }
    daily.clear();
    weekly.clear();
    halgyearly.clear();
    monthly.clear();
    yearly.clear();
    selectedSection = "";
    selectedSection = "";
    averageValue = null;
    averageValueString = null;
    selectedDuration = Durations.daily;
  }

  void fetchData() {
    // if(selectedSection == value) return;
    mapValuesForFilters(selectedDuration, selectedSection);
    getAverageForData();
    transformValueIfSleepIsSelected();
  }

  void setDurations(Durations duration) {
    selectedDuration = duration;
  }

  void getAverageForData() {
    if (selectedData.isEmpty) {
      averageValue = 0.0;
      notifyListeners();
      return;
    }
    double total = 0;
    int count = 0;
    selectedData.forEach((key, dataPoints) {
      for (var dataPoint in dataPoints) {
        total += num.parse(dataPoint.actualValue);
        count++;
      }
    });
    averageValue = count > 0 ? total / count : null;
    notifyListeners();
  }

  void transformValueIfSleepIsSelected() {
    if (selectedSection != "sleep") return;
    if (averageValue == null) {
      averageValueString = null;
      return;
    }
    averageValueString = DateUtil.millisToHourMin(averageValue?.toInt() ?? 0);
    averageValue = null;
    notifyListeners();
  }

  String firstNonEmptyValue(List<Vitals> dataPoints) {
    try {
      return dataPoints.firstWhere((dp) => dp.value.trim().isNotEmpty).value;
    } catch (e) {
      return "0"; // no non-empty value found
    }
  }

  String sumOfNonEmptyData(List<Vitals> list) {
    final now = DateTime.now().toLocal();
    final today = DateTime(now.year, now.month, now.day);

    var data = double.parse(list
        .where((dp) {
          final localDate = DateTime.parse(dp.timestamp);
          final normalized = DateTime(localDate.year, localDate.month, localDate.day);

          return normalized.isAtSameMomentAs(today);
        })
        .fold("0", (sum, dp) => (double.parse(sum) + double.parse(dp.value)).toString())
        .toString());
    var formattedString = data.toStringAsFixed(2);

    if (formattedString.endsWith('.00')) {
      return formattedString.substring(0, formattedString.length - 3);
    }
    return formattedString;
  }
}
