import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:async/src/result/result.dart';
import 'package:flutter/material.dart';
import 'package:health/health.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/watch_helper.dart' show WatchHelper;
import 'package:permission_handler/permission_handler.dart';

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

class HealthConnectHelper extends WatchHelper {
  final Health health = Health();

  final List<HealthDataType> _healthPermissions = [
    HealthDataType.ACTIVE_ENERGY_BURNED,
    HealthDataType.HEART_RATE,
    HealthDataType.STEPS,
    HealthDataType.BLOOD_OXYGEN,
    HealthDataType.BODY_TEMPERATURE,
    HealthDataType.DISTANCE_WALKING_RUNNING,
    HealthDataType.TOTAL_CALORIES_BURNED
  ];

  Map<String , List<Vitals>> mappedData = {};

  @override
  FutureOr<void> getHeartRate() async {
    try {
      final types = HealthDataType.HEART_RATE;
      final endDate = DateTime.now();
      // final startDate = endDate.subtract(Duration(days: 365));
      final startDate = endDate.subtract(Duration(days: 365));
      final data = await getHeartData(startDate, endDate, types);
      addDataToMap("heartRate",data );
    } catch (e) {
      print('Error getting heart rate: $e');
    }
  }

  @override
  FutureOr<void> getSleep() async {
    try {
      final types = HealthDataType.SLEEP_IN_BED;
      final endDate = DateTime.now();
      final startDate = endDate.subtract(Duration(days: 365));
      final data = await  getData(startDate, endDate, types);
      addDataToMap("sleep",data );
    } catch (e) {
      print('Error getting sleep data: $e');
    }
  }

  @override
  FutureOr<void> getSteps() async {
    try {
      final types = HealthDataType.STEPS;
      final endDate = DateTime.now();
      final startDate = endDate.subtract(Duration(days: 365));
      final data = await  getData(startDate, endDate, types);
      addDataToMap("steps",data );
      debugPrint('Steps Data: $data');
    } catch (e) {
      debugPrint('Error getting steps: $e');
    }
  }

  @override
  Future<void> getActivity() async {
    try {
      final types = HealthDataType.ACTIVE_ENERGY_BURNED;
      final endDate = DateTime.now();
      final startDate = endDate.subtract(Duration(days: 365));
      final data = await  getData(startDate, endDate, types);
      addDataToMap("activity",data );
      debugPrint('Activity Data: $data');
    } catch (e) {
      debugPrint('Error getting activity: $e');
    }
  }

  @override
  Future<dynamic> retrieveData() async {
    // String retData;
    // retData = Result.value(getMappedData()) as String;
    return Result.value(getMappedData());
    // return retData;
  }

  @override
  Future<dynamic> getBloodOxygen() async {
    try {
      final types = HealthDataType.BLOOD_OXYGEN;
      final endDate = DateTime.now();
      final startDate = endDate.subtract(Duration(days: 365));
      final data = await  getData(startDate, endDate, types);
      addDataToMapBloodOxygen("bloodOxygen", data);
    } catch (e) {
      debugPrint('Error getting blood oxygen: $e');
    }
  }

  @override
  Future<dynamic> getBodyTemperature() async {
    try {
      final types = HealthDataType.BODY_TEMPERATURE;
      final endDate = DateTime.now();
      final startDate = endDate.subtract(Duration(days: 365));
      final data = await  getData(startDate, endDate, types);
      addDataToMap("bodyTemperature",data );
    } catch (e) {
      debugPrint('Error getting body temp  erature: $e');
    }
  }

  @override
  FutureOr<void> getDistance() async {
    try {
      final types = HealthDataType.DISTANCE_WALKING_RUNNING;
      final endDate = DateTime.now();
      final startDate = endDate.subtract(Duration(days: 365));
      final data = await  getData(startDate, endDate, types);
      addDataToMap("distance",data );
    } catch (e) {
      debugPrint('Error getting distance: $e');
    }
  }

  @override
  Future<Result<bool>> initDevice() async {
    try {
      final types = _healthPermissions;
      final granted = await health.requestAuthorization(types);
      await Permission.activityRecognition.request();
      await Permission.location.request();
      await Health().requestHealthDataHistoryAuthorization();
      return Result.value(granted);
    } catch (e) {
      debugPrint('Authorization error: $e');
      return Result.error(false);
    }
  }

  getData(startTime, endTime,type) async {
    return await health.getHealthIntervalDataFromTypes(
      startDate: startTime,
      endDate: endTime,
      types: [type],
      interval: 3600,
    );
  }

  void addDataToMap(String s, data) {
    mappedData[s] = [];
    for (var point in data) {
      if (point.value is NumericHealthValue) {
        final numericValue = (point.value as NumericHealthValue).numericValue;
        String timestamp = DateTime.now().toIso8601String();

        try {
          if (point.dateFrom != null) {
            String tempTimestamp = point.dateFrom.toIso8601String();
            if (tempTimestamp.isNotEmpty) {
              timestamp = tempTimestamp;
            }
          }
        } catch (e) {
          debugPrint('Error converting dateFrom to ISO8601 for $s: $e');
        }

        Vitals vitals = Vitals(
          value: numericValue.toStringAsFixed(2),
          timestamp: timestamp
        );
        mappedData[s]?.add(vitals);
      }
    }
  }

  void addDataToMapBloodOxygen(String s, data) {
    mappedData[s] = [];
    for (var point in data) {
      if (point.value is NumericHealthValue) {
        final numericValue = (point.value as NumericHealthValue).numericValue;
        String timestamp = DateTime.now().toIso8601String();

        try {
          if (point.dateFrom != null) {
            String tempTimestamp = point.dateFrom.toIso8601String();
            if (tempTimestamp.isNotEmpty) {
              timestamp = tempTimestamp;
            }
          }
        } catch (e) {
          debugPrint('Error converting dateFrom to ISO8601 for $s: $e');
        }

        point.value = NumericHealthValue(
          numericValue: numericValue * 100,
        );
        Vitals vitals = Vitals(
          value: (point.value as NumericHealthValue).numericValue.toStringAsFixed(2),
          timestamp: timestamp
        );
        mappedData[s]?.add(vitals);
      }
    }
  }

  getMappedData() {
    return jsonEncode({
      "heartRate": (mappedData["heartRate"] ?? []).map((v) => v.toJson()).toList(),
      "sleep": (mappedData["sleep"] ?? []).map((v) => v.toJson()).toList(),
      "steps": (mappedData["steps"] ?? []).map((v) => v.toJson()).toList(),
      "activity": (mappedData["activity"] ?? []).map((v) => v.toJson()).toList(),
      "bloodOxygen": (mappedData["bloodOxygen"] ?? []).map((v) => v.toJson()).toList(),
      "bodyTemperature": (mappedData["bodyTemperature"] ?? []).map((v) => v.toJson()).toList(),
      "distance": (mappedData["distance"] ?? []).map((v) => v.toJson()).toList(),
    });
  }

  getHeartData(DateTime startDate, DateTime endDate, HealthDataType types) async {
    return await health.getHealthDataFromTypes(
      startTime: startDate,
      endTime: endDate,
      types: [types],
    );
  }
}
