import 'dart:async';

import 'package:doctor_app_flutter/core/enum/filter_type.dart';
import 'package:doctor_app_flutter/core/enum/patient_type.dart';
import 'package:doctor_app_flutter/core/enum/view_state.dart';
import 'package:doctor_app_flutter/core/model/patient_muse/PatientSearchRequestModel.dart';
import 'package:doctor_app_flutter/core/service/patient/out_patient_service.dart';
import 'package:doctor_app_flutter/core/service/patient/patientInPatientService.dart';
import 'package:doctor_app_flutter/core/service/special_clinics/special_clinic_service.dart';
import 'package:doctor_app_flutter/core/model/dashboard/get_special_clinical_care_mapping_List_Respose_Model.dart';
import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart';
import 'package:doctor_app_flutter/utils/date-utils.dart';
import 'package:doctor_app_flutter/utils/utils.dart';

import '../../locator.dart';
import 'base_view_model.dart';

class PatientSearchViewModel extends BaseViewModel {
  OutPatientService _outPatientService = locator<OutPatientService>();
  SpecialClinicsService _specialClinicsService = locator<SpecialClinicsService>();

  List<PatiantInformtion> get patientList => _outPatientService.patientList;

  List<GetSpecialClinicalCareMappingListResponseModel> get specialClinicalCareMappingList => _specialClinicsService.specialClinicalCareMappingList;

  List<PatiantInformtion> filterData = [];

  DateTime? selectedFromDate;
  DateTime? selectedToDate;

  int firstSubsetIndex = 0;
  int inPatientPageSize = 20;
  int lastSubsetIndex = 20;
  String noDataFoundText = "";

  List<String> InpatientClinicList = [];

  searchData(String str) {
    var strExist = str.length > 0 ? true : false;
    if (strExist) {
      filterData = [];
      for (var i = 0; i < _outPatientService.patientList.length; i++) {
        String firstName = _outPatientService.patientList[i].firstName!.toUpperCase();
        String lastName = _outPatientService.patientList[i].lastName!.toUpperCase();
        String mobile = _outPatientService.patientList[i].mobileNumber!.toUpperCase();
        String patientID = _outPatientService.patientList[i].patientId.toString();

        if (firstName.contains(str.toUpperCase()) || lastName.contains(str.toUpperCase()) || mobile.contains(str) || patientID.contains(str)) {
          filterData.add(_outPatientService.patientList[i]);
        }
      }
      notifyListeners();
    } else {
      filterData = _outPatientService.patientList;
      notifyListeners();
    }
  }

  getOutPatient(PatientSearchRequestModel patientSearchRequestModel, {bool isLocalBusy = false}) async {
    if (isLocalBusy) {
      setState(ViewState.BusyLocal);
    } else {
      setState(ViewState.Busy);
    }
    await getDoctorProfile(isGetProfile: true);
    patientSearchRequestModel.loginDoctorID = doctorProfile!.doctorID;
    patientSearchRequestModel.doctorID = doctorProfile!.doctorID;
    patientSearchRequestModel.clinicID = doctorProfile!.clinicID; // Added clinic filter to avoid fetching all based on DoctorIDh
    await _outPatientService.getOutPatient(patientSearchRequestModel);
    if (_outPatientService.hasError) {
      error = _outPatientService.error;
      if (isLocalBusy) {
        setState(ViewState.ErrorLocal);
      } else {
        setState(ViewState.Error);
      }
    } else {
      filterData = _outPatientService.patientList;
      setState(ViewState.Idle);
    }
  }

  sortOutPatient({bool isDes = false}) {
    if (isDes)
      filterData = filterData.reversed.toList();
    else
      filterData = filterData.reversed.toList();
    setState(ViewState.Idle);
  }

  getPatientFileInformation(PatientSearchRequestModel patientSearchRequestModel, {bool isLocalBusy = false}) async {
    setState(ViewState.Busy);
    await _outPatientService.getPatientFileInformation(patientSearchRequestModel);
    if (_outPatientService.hasError) {
      error = _outPatientService.error;
      setState(ViewState.Error);
    } else {
      filterData = _outPatientService.patientList;
      setState(ViewState.Idle);
    }
  }

  getPatientBasedOnDate({item, PatientSearchRequestModel? patientSearchRequestModel, PatientType? selectedPatientType, bool? isSearchWithKeyInfo, OutPatientFilterType? outPatientFilterType}) async {
    String dateTo;
    String dateFrom;
    if (OutPatientFilterType.Previous == outPatientFilterType) {
      selectedFromDate = DateTime(DateTime.now().year, DateTime.now().month - 1, DateTime.now().day);
      selectedToDate = DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day - 1);
      dateTo = AppDateUtils.convertDateToFormat(selectedToDate!, 'yyyy-MM-dd');
      dateFrom = AppDateUtils.convertDateToFormat(selectedFromDate!, 'yyyy-MM-dd');
    } else if (OutPatientFilterType.NextWeek == outPatientFilterType) {
      dateTo = AppDateUtils.convertDateToFormat(DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day + 7), 'yyyy-MM-dd');

      dateFrom = AppDateUtils.convertDateToFormat(DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day + 1), 'yyyy-MM-dd');
    } else {
      dateFrom = AppDateUtils.convertDateToFormat(DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day), 'yyyy-MM-dd');
      dateTo = AppDateUtils.convertDateToFormat(DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day), 'yyyy-MM-dd');
    }
    PatientSearchRequestModel currentModel = PatientSearchRequestModel();
    currentModel.patientID = patientSearchRequestModel!.patientID;
    currentModel.firstName = patientSearchRequestModel.firstName;
    currentModel.lastName = patientSearchRequestModel.lastName;
    currentModel.middleName = patientSearchRequestModel.middleName;
    currentModel.doctorID = patientSearchRequestModel.doctorID;
    currentModel.from = dateFrom;
    currentModel.to = dateTo;
    await getOutPatient(currentModel, isLocalBusy: true);
    filterData = _outPatientService.patientList;
  }

  PatientInPatientService _inPatientService = locator<PatientInPatientService>();

  List<PatiantInformtion> get inPatientList => _inPatientService.inPatientList;

  List<PatiantInformtion> get myIinPatientList => _inPatientService.myInPatientList;
  List<PatiantInformtion> mainList = [];
  List<PatiantInformtion> filteredInPatientItems = [];
  List<PatiantInformtion> filteredMyInPatientItems = [];
  PatientSearchRequestModel? requestModel;
  bool isVidaPlusProject = false;
  bool paginationLoading = false;

  /// Resets all state variables in the ViewModel to their default values.
  void resetViewModel() {
    // 1. Clear all lists that hold patient data.
    mainList.clear();
    filteredInPatientItems.clear();
    filteredMyInPatientItems.clear();
    _inPatientService.inPatientList.clear();
    _inPatientService.myInPatientList.clear();

    // 2. Reset the pagination request model and flags.
    requestModel = null;
    isVidaPlusProject = false;
    paginationLoading = false;

    // 3. Reset pagination counters (if you have them).
    // Based on your code, you have a `resetInPatientPagination` function that does this.
    resetInPatientPagination();

    // 4. Clear any existing error messages.
    error = null;

    // 5. Set the view state back to Idle.
    // It's good practice to notify listeners after a major state change.
    setState(ViewState.Idle);
  }
  Future getInPatientList(PatientSearchRequestModel requestModel, {bool isMyInpatient = false, bool isLocalBusy = false,  bool isVidaPlusProject = false, bool isForceFullRefresh = false}) async {
    resetViewModel();
    await getDoctorProfile();
    if (isLocalBusy) {
      setState(ViewState.BusyLocal);
    } else {
      setState(ViewState.Busy);
    }
    if (inPatientList.length == 0 || isForceFullRefresh) await _inPatientService.getInPatientList(requestModel, false, isVidaPlusProject: isVidaPlusProject);
    if(isVidaPlusProject) {
      this.requestModel = requestModel;
      this.isVidaPlusProject = isVidaPlusProject;
    }
    if (_inPatientService.hasError) {
      error = _inPatientService.error;
      if (isLocalBusy) {
        setState(ViewState.ErrorLocal);
      } else {
        setState(ViewState.Error);
      }
    } else {
      setDefaultInPatientList();
      generateInpatientClinicList();
      setState(ViewState.Idle);
    }
  }
  FutureOr<void> paginatedInPatientCall(String? selectedClinicName, String? query, bool? isSortDes,{bool isMyInPatient = false,bool isAllClinic = false }) async {

    if(isVidaPlusProject == false) return;
    if(paginationLoading == true) return;

    if(this.requestModel == null) return;
    PatientSearchRequestModel requestModel = this.requestModel!;
    requestModel.pageIndex =  (requestModel.pageIndex??0)+1;
    paginationLoading = true;
    notifyListeners();
    await _inPatientService.getInPatientList(requestModel, false, isVidaPlusProject: isVidaPlusProject);
    paginationLoading = false;
    if (_inPatientService.hasError) {
      error = _inPatientService.error;
      requestModel.pageIndex = (requestModel.pageIndex??1) - 1 ;
    } else {
      this.requestModel = requestModel;
      if (inPatientList.isEmpty ==  true) {
        requestModel.pageIndex = (requestModel.pageIndex??1) - 1 ;
        Utils.showErrorToast(noDataFoundText);
        return;
      }
      await setDefaultInPatientList(isFromPagination: true);
      generateInpatientClinicList(isFromPagination: true);
      sortInPatient(isDes:isSortDes == true, isAllClinic: isAllClinic, isMyInPatient: isMyInPatient );
      filterSearchResults(query!, isAllClinic: isAllClinic, isMyInPatient: isMyInPatient);
      filterByClinic(clinicName: selectedClinicName!);
    }
    notifyListeners();

  }

  sortInPatient({bool isDes = false, bool isAllClinic = false, bool isMyInPatient = false}) {
    if (isMyInPatient
        ? myIinPatientList.length > 0
        : isAllClinic
            ? mainList.length > 0
            : filteredInPatientItems.length > 0) {
      List<PatiantInformtion> localInPatient = isMyInPatient
          ? [...filteredMyInPatientItems]
          : isAllClinic
              ? [...mainList]
              : [...filteredInPatientItems];
      if (isDes)
        localInPatient.sort((PatiantInformtion a, PatiantInformtion b) => b.admissionDateWithDateTimeForm!.compareTo(a.admissionDateWithDateTimeForm!));
      else
        localInPatient.sort((PatiantInformtion a, PatiantInformtion b) => a.admissionDateWithDateTimeForm!.compareTo(b.admissionDateWithDateTimeForm!));
      if (isMyInPatient) {
        filteredMyInPatientItems.clear();
        filteredMyInPatientItems.addAll(localInPatient);
      } else if (isAllClinic) {
        resetInPatientPagination();
        filteredInPatientItems.addAll(localInPatient.sublist(firstSubsetIndex, lastSubsetIndex));
      } else {
        filteredInPatientItems.clear();
        filteredInPatientItems.addAll(localInPatient);
      }
    }
    setState(ViewState.Idle);
  }

  resetInPatientPagination() {
    filteredInPatientItems.clear();
    firstSubsetIndex = 0;
    lastSubsetIndex = inPatientPageSize - 1;
    requestModel?.pageIndex = 0;
  }

  Future setDefaultInPatientList({isFromPagination = false}) async {
    setState(ViewState.BusyLocal);
    await getDoctorProfile();
    if(isFromPagination == false) {
      resetInPatientPagination();
    }
    if (inPatientList.length > 0) {
      // lastSubsetIndex = (inPatientList.length < inPatientPageSize - 1 ? inPatientList.length : inPatientPageSize - 1);
      mainList.addAll(inPatientList);
      filteredInPatientItems.addAll(inPatientList);
    }

    if (myIinPatientList.length > 0) {
      filteredMyInPatientItems.addAll(myIinPatientList);
    }
    setState(ViewState.Idle);
  }

  generateInpatientClinicList({bool isFromPagination = false}) {
    if(isFromPagination == false) {
      InpatientClinicList.clear();
    }
    inPatientList.forEach((element) {
      if (!InpatientClinicList.contains(element.clinicDescription)) {
        InpatientClinicList.add(element.clinicDescription!);
      }
    });
  }

  addOnFilteredList() {
    if (lastSubsetIndex < inPatientList.length) {
      firstSubsetIndex = firstSubsetIndex + (inPatientList.length - lastSubsetIndex < inPatientPageSize - 1 ? inPatientList.length - lastSubsetIndex : inPatientPageSize - 1);
      lastSubsetIndex = lastSubsetIndex + (inPatientList.length - lastSubsetIndex < inPatientPageSize - 1 ? inPatientList.length - lastSubsetIndex : inPatientPageSize - 1);
      filteredInPatientItems.addAll(inPatientList.sublist(firstSubsetIndex, lastSubsetIndex));
      setState(ViewState.Idle);
    }
  }

  removeOnFilteredList() {
    if (lastSubsetIndex - inPatientPageSize - 1 > 0) {
      filteredInPatientItems.removeAt(lastSubsetIndex - inPatientPageSize - 1);
      setState(ViewState.Idle);
    }
  }

  filterByHospital({required int hospitalId}) {
    filteredInPatientItems = [];
    for (var i = 0; i < inPatientList.length; i++) {
      if (inPatientList[i].projectId == hospitalId) {
        filteredInPatientItems.add(inPatientList[i]);
      }
    }
    notifyListeners();
  }

  filterByClinic({required String clinicName}) {
    if(clinicName.isEmpty) return;
    filteredInPatientItems = [];
    for (var i = 0; i < mainList.length; i++) {
      if (mainList[i].clinicDescription == clinicName) {
        filteredInPatientItems.add(mainList[i]);
      }
    }
    notifyListeners();
  }

  void resetFilters(){
    filteredInPatientItems = mainList;
  }

  void clearPatientList() {
    _inPatientService.inPatientList = [];
    _inPatientService.myInPatientList = [];
  }

  void filterSearchResults(String query, {bool isAllClinic = false, bool isMyInPatient = false}) {
    var strExist = query.length > 0 ? true : false;

    if (isMyInPatient) {
      List<PatiantInformtion> localFilteredMyInPatientItems = [...filteredMyInPatientItems];

      if (strExist) {
        filteredMyInPatientItems.clear();
        for (var i = 0; i < localFilteredMyInPatientItems.length; i++) {
          String firstName = localFilteredMyInPatientItems[i].firstName!.toUpperCase();
          String lastName = localFilteredMyInPatientItems[i].lastName!.toUpperCase();
          String mobile = localFilteredMyInPatientItems[i].mobileNumber!.toUpperCase();
          String patientID = localFilteredMyInPatientItems[i].patientId.toString();

          if (firstName.contains(query.toUpperCase()) || lastName.contains(query.toUpperCase()) || mobile.contains(query) || patientID.contains(query)) {
            filteredMyInPatientItems.add(localFilteredMyInPatientItems[i]);
          }
        }
        notifyListeners();
      } else {
        if (filteredMyInPatientItems.length > 0) filteredMyInPatientItems.clear();
        filteredMyInPatientItems.addAll(localFilteredMyInPatientItems);
        notifyListeners();
      }
    } else {
      if (isAllClinic) {
        if (strExist) {
          filteredInPatientItems = [];
          for (var i = 0; i < mainList.length; i++) {
            String firstName = mainList[i].firstName!.toUpperCase();
            String lastName = mainList[i].lastName!.toUpperCase();
            String mobile = mainList[i].mobileNumber!.toUpperCase();
            String patientID = mainList[i].patientId.toString();

            if (firstName.contains(query.toUpperCase()) || lastName.contains(query.toUpperCase()) || mobile.contains(query) || patientID.contains(query)) {
              filteredInPatientItems.add(mainList[i]);
            }
          }
          notifyListeners();
        } else {
          if (mainList.length > 0) filteredInPatientItems.clear();
          filteredInPatientItems.addAll(mainList);
          notifyListeners();
        }
      } else {
        List<PatiantInformtion> localFilteredInPatientItems = [...filteredInPatientItems];

        if (strExist) {
          filteredInPatientItems.clear();
          for (var i = 0; i < localFilteredInPatientItems.length; i++) {
            String firstName = localFilteredInPatientItems[i].firstName!.toUpperCase();
            String lastName = localFilteredInPatientItems[i].lastName!.toUpperCase();
            String mobile = localFilteredInPatientItems[i].mobileNumber!.toUpperCase();
            String patientID = localFilteredInPatientItems[i].patientId.toString();

            if (firstName.contains(query.toUpperCase()) || lastName.contains(query.toUpperCase()) || mobile.contains(query) || patientID.contains(query)) {
              filteredInPatientItems.add(localFilteredInPatientItems[i]);
            }
          }
          notifyListeners();
        } else {
          if (localFilteredInPatientItems.length > 0) filteredInPatientItems.clear();
          filteredInPatientItems.addAll(localFilteredInPatientItems);
          notifyListeners();
        }
      }
    }
  }

  getSpecialClinicalCareMappingList(clinicId, {bool isLocalBusy = false}) async {
    if (isLocalBusy) {
      setState(ViewState.BusyLocal);
    } else {
      setState(ViewState.Busy);
    }
    await _specialClinicsService.getSpecialClinicalCareMappingList(clinicId);
    if (_specialClinicsService.hasError) {
      error = _specialClinicsService.error;
      if (isLocalBusy) {
        setState(ViewState.ErrorLocal);
      } else {
        setState(ViewState.Error);
      }
    } else {
      setState(ViewState.Idle);
    }
  }


  flushSelectedDates(){
    selectedFromDate = null;
    selectedToDate =  null;
  }
}
