import 'dart:math';

import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctors_list_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/doctor_list_api_response.dart' show RegionList, PatientDoctorAppointmentList, DoctorList, PatientDoctorAppointmentListByRegion;
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart' show HospitalsModel;

class DoctorMapper{
  static Future<RegionList> getMappedDoctor(List<DoctorsListResponseModel> doctorList,
      {bool isArabic = false,double lat = 0.0,double long = 0.0}) async {
    RegionList regionList = RegionList();


    for (var element in doctorList) {
      String? region = element.getRegionName(isArabic);
      if (region == null) continue;

      var regionDoctorList = regionList.registeredDoctorMap?.putIfAbsent(region, () => PatientDoctorAppointmentListByRegion());

      List<PatientDoctorAppointmentList>? targetList = element.isHMC == true
          ? regionDoctorList?.hmcDoctorList
          : regionDoctorList?.hmgDoctorList;

      var doctorByHospital = targetList
              ?.where((clinic) =>
                  clinic.filterName ==
                  element.getProjectCompleteNameWithLocale(isArabic: isArabic))
              .toList() ??
          [];

      if (doctorByHospital.isNotEmpty) {
        doctorByHospital.first.patientDoctorAppointmentList?.add(element);
      } else {
        var newAppointment = PatientDoctorAppointmentList(
          filterName:
              element.getProjectCompleteNameWithLocale(isArabic: isArabic),
          distanceInKMs: element.projectDistanceInKiloMeters.toString(),
          projectTopName: element.projectTopName,
          projectBottomName: element.projectBottomName,
          patientDoctorAppointment: element,
          isHMC: element.isHMC
        );
        if(element.projectDistanceInKiloMeters!= null ){
          if(regionDoctorList!.distance>element.projectDistanceInKiloMeters!){
            regionDoctorList.distance = element.projectDistanceInKiloMeters!;
          }
          if (element.isHMC == true &&
              element.projectDistanceInKiloMeters! <
                  regionDoctorList.hmcDistance) {
            regionDoctorList.hmcDistance = element.projectDistanceInKiloMeters!;
          } else if (element.projectDistanceInKiloMeters! <
              regionDoctorList.hmgDistance) {
            regionDoctorList.hmgDistance = element.projectDistanceInKiloMeters!;
          }
        }else
        if (lat != 0&&
            long != 0 && element.latitude != null && element.longitude != null) {


          double distance =  calculateDistance(lat.toDouble(), long.toDouble(), double.parse(element.latitude!), double.parse(element.longitude!));
          if(distance<0){
            distance *= -1;
          }
          if(regionDoctorList!.distance>distance){
            regionDoctorList.distance = distance;
          }
          if (element.isHMC == true &&
              (element.projectDistanceInKiloMeters??0) <
                  regionDoctorList.hmcDistance) {
            regionDoctorList.hmcDistance = element.projectDistanceInKiloMeters??0;
          } else if ((element.projectDistanceInKiloMeters??0) <
              regionDoctorList.hmgDistance) {
            regionDoctorList.hmgDistance = element.projectDistanceInKiloMeters??0;
          }
        }
        targetList?.add(newAppointment);
      }




      regionDoctorList?.hmcSize = regionDoctorList.hmcDoctorList?.length ?? 0;
      regionDoctorList?.hmgSize = regionDoctorList.hmgDoctorList?.length ?? 0;

      regionList.registeredDoctorMap?[region] = regionDoctorList;
    }

    return regionList;
  }
  static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
    var pi = 3.142;
    const double R = 6371;
    double dLat = (lat2 - lat1) * pi / 180;
    double dLon = (lon2 - lon1) * pi / 180;
    double a = sin(dLat / 2) * sin(dLat / 2) +
        cos(lat1 * pi / 180) * cos(lat2 * pi / 180) * sin(dLon / 2) * sin(dLon / 2);
    double c = 2 * atan2(sqrt(a), sqrt(1 - a));
    return R * c;
  }

  static Future<RegionList> sortList(bool isGPSEnabled, RegionList unsorted, )  async {
    if(isGPSEnabled){
      if(unsorted.registeredDoctorMap == null) return unsorted;
      var sortedMap = Map.fromEntries(
        unsorted.registeredDoctorMap!.entries.toList()
          ..sort((a, b) => a.value!.distance.compareTo(b.value!.distance)),
      );

      unsorted.registeredDoctorMap = sortedMap;
      return unsorted;

    }

    List<String>? keys = unsorted.registeredDoctorMap?.keys.toList();
    keys?.sort();

    if (keys == null) return unsorted;
    Map<String, PatientDoctorAppointmentListByRegion> sortedMap = {};
    for (var key in keys) {
      sortedMap[key] = unsorted.registeredDoctorMap![key]!;
    }
    unsorted.registeredDoctorMap = sortedMap;
    return unsorted;
  }

  static Future<RegionList> getMappedHospitals(
    List<HospitalsModel> hospitalList, {
    bool isArabic = false, double lat = 0.0,double lng = 0.0
  }) async {
    final regionList = RegionList();
    for (final hospital in hospitalList) {
      final region = hospital.getRegionName(isArabic);
      if (region == null) continue;

      final regionData = regionList.registeredDoctorMap?.putIfAbsent(
        region,
        () => PatientDoctorAppointmentListByRegion(),
      );

      List<PatientDoctorAppointmentList>? targetList = hospital.isHMC == true
          ? regionData?.hmcDoctorList
          : regionData?.hmgDoctorList;

      List<PatientDoctorAppointmentList> existingEntry = targetList
              ?.where(
                (entry) => entry.filterName == hospital.getName(isArabic),
              )
              .toList() ??
          [];

      if (existingEntry.isNotEmpty) {
        existingEntry.first.hospitalList.add(hospital);
      } else {
        final newEntry = PatientDoctorAppointmentList(
            filterName: hospital.name,
            distanceInKMs: hospital.distanceInKilometers?.toString(),
            projectTopName: hospital.name,
            projectBottomName: hospital.name,
            model: hospital,
        isHMC: hospital.isHMC);

        final distance = hospital.distanceInKilometers;

        if (distance != null) {
          if (regionData!.distance > distance) {
            regionData.distance = distance;
          }
          if (hospital.isHMC == true && distance < regionData.hmcDistance) {
            regionData.hmcDistance = distance;
          } else if (distance < regionData.hmgDistance) {
            regionData.hmgDistance = distance;
          }
        } else if ( lat != 0.0&&
            lng != 0.0 &&
            hospital.latitude != null &&
            hospital.longitude != null) {
          double calculatedDistance = calculateDistance(
            lat,
            lng,
            double.parse(hospital.latitude!),
            double.parse(hospital.longitude!),
          ).abs();

          if (regionData!.distance > calculatedDistance) {
            regionData.distance = calculatedDistance;
          }
          if (hospital.isHMC == true &&
              calculatedDistance < regionData.hmcDistance) {
            regionData.hmcDistance = calculatedDistance;
          } else if (calculatedDistance < regionData.hmgDistance) {
            regionData.hmgDistance = calculatedDistance;
          }
        }
        targetList?.add(newEntry);
      }

      regionData?.hmcSize = regionData.hmcDoctorList?.length ?? 0;
      regionData?.hmgSize = regionData.hmgDoctorList?.length ?? 0;
      regionList.registeredDoctorMap?[region] = regionData;
    }

    return regionList;
  }
}