import 'dart:math';

import 'package:hmg_patient_app_new/core/common_models/data_points.dart';
import 'package:intl/intl.dart';

import 'model/vitals_data_model.dart';

enum Durations {
  daily("daily"),
  weekly("weekly"),
  monthly("monthly"),
  halfYearly("halfYearly"),
  yearly("yearly");

  final String value;

  const Durations(this.value);
}

class HealthDataTransformation {
  Map<String, List<DataPoint>> transformVitalsToDataPoints(
    VitalsWRTType vitals,
    String filterType,
    String selectedSection,
  ) {
    final Map<String, List<DataPoint>> dataPointMap = {};
    Map<String, List<Vitals>> data = vitals.getVitals();
    // Group data based on the filter type
    Map<String, List<Vitals>> groupedData = {};
    // List<List<Vitals> >  items =  data.values.toList();
    List<String> keys = data.keys.toList();
    var count = 0;
    List<Vitals> item = data[selectedSection] ?? [];
    // for(var item in items) {
    List<DataPoint> dataPoints = [];

    for (var vital in item) {
      String key = "";
      if (vital.value == "" || vital.timestamp == "") continue;

      DateTime parseDate;
      try {
        parseDate = DateTime.parse(vital.timestamp);
      } catch (e) {
        print('Error parsing timestamp "${vital.timestamp}": $e');
        continue; // Skip this vital if timestamp is invalid
      }

      var currentDate = normalizeToStartOfDay(DateTime.now());
      if (filterType == Durations.daily.value) {
        if (isBetweenInclusive(parseDate, currentDate, DateTime.now())) {
          key = DateFormat('yyyy-MM-dd HH').format(parseDate);
          groupedData.putIfAbsent(key, () => []).add(vital);
        } // Group by hour
      } else if (filterType == Durations.weekly.value) {
        if (isBetweenInclusive(parseDate, currentDate.subtract(Duration(days: 7)), DateTime.now())) {
          key = DateFormat('yyyy-MM-dd').format(parseDate);
          groupedData.putIfAbsent(key, () => []).add(vital);
        } // Group by day
      } else if (filterType == Durations.monthly.value) {
        if (isBetweenInclusive(parseDate, currentDate.subtract(Duration(days: 30)), DateTime.now())) {
          print("the value for the monthly filter is ${vital.value} with the timestamp ${vital.timestamp} and the current date is $currentDate and the parse date is $parseDate");
          key = DateFormat('yyyy-MM-dd').format(parseDate);
          groupedData.putIfAbsent(key, () => []).add(vital);
        } // Group by day
      } else if (filterType == Durations.halfYearly.value || filterType == Durations.yearly.value) {
        if (isBetweenInclusive(parseDate, currentDate.subtract(Duration(days: filterType == Durations.halfYearly.value ? 180 : 365)), DateTime.now())) {
          key = DateFormat('yyyy-MM').format(parseDate);
          groupedData.putIfAbsent(key, () => []).add(vital);
        } // Group by month
      } else {
        throw ArgumentError('Invalid filter type');
      }
    }
    print("the size of groupData is ${groupedData.values.length}");

    // Process grouped data
    groupedData.forEach((key, values) {
      double sum = values.fold(0, (acc, v) => acc + num.parse(v.value));
      double mean = sum / values.length;
      if (selectedSection == "bodyOxygen" || selectedSection == "bodyTemperature") {
        mean = sum / values.length;
      } else {
        mean = sum;
      }

      double finalValue = mean;
      print("the final value is $finalValue for the key $key with the original values ${values.map((v) => v.value).toList()} and uom is ${values.first.unitOfMeasure}");
      dataPoints.add(DataPoint(
        value: smartScale(finalValue),
        label: key,
        actualValue: finalValue.toStringAsFixed(2),
        displayTime: key,
        unitOfMeasurement: values.first.unitOfMeasure,
        time: DateTime.parse(values.first.timestamp),
      ));
    });

    dataPointMap[filterType] = dataPoints;
    // }
    return dataPointMap;
  }

  double smartScale(double number) {
    // if (number <= 0) return 0;
    // final _random = Random();
    // double ratio = number / 100;
    //
    // double scalingFactor = ratio > 1 ? 100 / number : 100;
    //
    // double result = (number / 100) * scalingFactor;
    // print("the ratio is ${ratio.toInt()+1}");
    // double max = (100+_random.nextInt(ratio.toInt()+10)).toDouble();
    //
    // return result.clamp(0, max);

    if (number <= 0) return 0;

    final random = Random();

    // Smooth compression scaling
    double baseScaled = number < 20 ? number : 100 * (number / (number + 100));

    // Random factor between 0.9 and 1.1 (±10%)
    double randomFactor = number < 20 ? random.nextDouble() * 1.5 : 0.9 + random.nextDouble() * 0.2;

    double result = baseScaled * randomFactor;

    return result.clamp(0, 100);
  }

  DateTime normalizeToStartOfDay(DateTime date) {
    return DateTime(date.year, date.month, date.day);
  }

  bool isBetweenInclusive(
    DateTime target,
    DateTime start,
    DateTime end,
  ) {
    return !normalizeToStartOfDay(target).isBefore(start) && !normalizeToStartOfDay(target).isAfter(end);
  }
}
