import 'package:doctor_app_flutter/config/config.dart';
import 'package:doctor_app_flutter/core/enum/filter_type.dart';
import 'package:doctor_app_flutter/core/enum/view_state.dart';
import 'package:doctor_app_flutter/core/model/labs/lab_order_result.dart';
import 'package:doctor_app_flutter/core/model/labs/lab_result.dart';
import 'package:doctor_app_flutter/core/model/labs/patient_lab_orders.dart';
import 'package:doctor_app_flutter/core/model/labs/patient_lab_special_result.dart';
import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart';
import 'package:doctor_app_flutter/core/model/procedure/ControlsModel.dart';
import 'package:doctor_app_flutter/core/model/procedure/categories_procedure.dart' as cpe;
import 'package:doctor_app_flutter/core/model/procedure/categories_procedure.dart';
import 'package:doctor_app_flutter/core/model/procedure/get_ordered_procedure_model.dart';
import 'package:doctor_app_flutter/core/model/procedure/post_procedure_req_model.dart';
import 'package:doctor_app_flutter/core/model/procedure/procedure_templateModel.dart';
import 'package:doctor_app_flutter/core/model/procedure/procedure_template_details_model.dart';
import 'package:doctor_app_flutter/core/model/procedure/procedure_valadate_model.dart';
import 'package:doctor_app_flutter/core/model/procedure/procedure_valadate_request_model.dart';
import 'package:doctor_app_flutter/core/model/procedure/update_procedure_request_model.dart';
import 'package:doctor_app_flutter/core/model/radiology/final_radiology.dart';
import 'package:doctor_app_flutter/core/service/AnalyticsService.dart';
import 'package:doctor_app_flutter/core/service/patient_medical_file/lab_order/labs_service.dart';
import 'package:doctor_app_flutter/core/service/patient_medical_file/procedure/procedure_service.dart';
import 'package:doctor_app_flutter/core/service/patient_medical_file/radiology/radiology_service.dart';
import 'package:doctor_app_flutter/core/viewModel/base_view_model.dart';
import 'package:doctor_app_flutter/locator.dart';
import 'package:doctor_app_flutter/screens/procedures/procedure_type.dart';
import 'package:doctor_app_flutter/utils/dr_app_toast_msg.dart';
import 'package:doctor_app_flutter/utils/utils.dart';
import 'package:doctor_app_flutter/widgets/shared/loader/gif_loader_dialog_utils.dart';
import 'package:flutter/cupertino.dart';

import '../service/patient_medical_file/prescription/prescription_service.dart';

class ProcedureViewModel extends BaseViewModel {
  //TODO Hussam clean it
  FilterType filterType = FilterType.Clinic;
  bool hasError = false;
  ProcedureService _procedureService = locator<ProcedureService>();
  PrescriptionService _prescriptionService = locator<PrescriptionService>();

  List<GetOrderedProcedureModel> get procedureList => _procedureService.procedureList;

  List<ProcedureValadteModel> get valadteProcedureList => _procedureService.valadteProcedureList;

  List<CategoriseProcedureModel> get categoriesList => _procedureService.categoriesList;

  List<dynamic> get categoryList => _procedureService.categoryList;
  RadiologyService _radiologyService = locator<RadiologyService>();
  LabsService _labsService = locator<LabsService>();
  List<FinalRadiologyList> _finalRadiologyListClinic = [];
  List<FinalRadiologyList> _finalRadiologyListHospital = [];

  List<FinalRadiologyList> get finalRadiologyList => filterType == FilterType.Clinic ? _finalRadiologyListClinic : _finalRadiologyListHospital;

  List<FinalRadiology> get radiologyList => _radiologyService.finalRadiologyList;

  List<PatientLabOrders> get patientLabOrdersList => _labsService.patientLabOrdersList;

  List<LabOrderResult> get labOrdersResultsList => _labsService.labOrdersResultsList;

  List<ProcedureTempleteDetailsModel> get procedureTemplate => _procedureService.templateList;
  List<ProcedureTempleteDetailsModelList> templateList = [];

  List<ProcedureTempleteDetailsModel> get procedureTemplateDetails => _procedureService.templateDetailsList;

  bool _isRadiologyVIDAPlus = false;

  bool get isRadiologyVIDAPlus => _isRadiologyVIDAPlus;

  bool get isPrincipalCovered_ => _prescriptionService.isDiagnosisCovered;

  Future getProcedure({int? mrn, String? patientType, int? appointmentNo, bool isLocalBusy = false}) async {
    hasError = false;
    await getDoctorProfile();
    if (isLocalBusy)
      setState(ViewState.BusyLocal);
    else
      setState(ViewState.Busy);
    await _procedureService.getProcedure(mrn: mrn, appointmentNo: appointmentNo);
    if (_procedureService.hasError) {
      error = _procedureService.error;
      if (patientType == "7")
        setState(ViewState.ErrorLocal);
      else
        setState(ViewState.Error);
    } else
      setState(ViewState.Idle);
  }

  Future getProcedureCategory({String? categoryName, String? categoryID, patientId, bool isLocalBusy = false}) async {
    if (categoryName == null) return;
    hasError = false;
    if (isLocalBusy)
      setState(ViewState.BusyLocal);
    else
      setState(ViewState.Busy);
    await _procedureService.getProcedureCategory(categoryName: categoryName, categoryID: categoryID, patientId: patientId);
    if (_procedureService.hasError) {
      error = _procedureService.error;
      setState(ViewState.ErrorLocal);
    } else
      setState(ViewState.Idle);
  }

  Future getCategory() async {
    hasError = false;
    //_insuranceCardService.clearInsuranceCard();
    setState(ViewState.Busy);
    await _procedureService.getCategory();
    if (_procedureService.hasError) {
      error = _procedureService.error;
      setState(ViewState.ErrorLocal);
    } else
      setState(ViewState.Idle);
  }

  Future getProcedureTemplate({String? categoryID, bool isLocalBusy = false, BuildContext? context}) async {
    if (isLocalBusy) {
      setState(ViewState.BusyLocal);
    } else {
      setState(ViewState.Busy);
    }
    await _procedureService.getProcedureTemplate(categoryID: categoryID, isLocalBusy: false);
    if (_procedureService.hasError) {
      error = _procedureService.error;
      setState(ViewState.ErrorLocal);
    } else
      setTemplateListDependOnId();
    setState(ViewState.Idle);
  }

  setTemplateListDependOnId() {
    templateList.clear();
    procedureTemplate.forEach((element) {
      List<ProcedureTempleteDetailsModelList> templateListData = templateList.where((elementTemplate) => elementTemplate.templateId == element.templateID).toList();

      if (templateListData.length != 0) {
        templateList[templateList.indexOf(templateListData[0])].procedureTemplate.add(element);
      } else {
        var template = ProcedureTempleteDetailsModelList(templateName: element.templateName, templateId: element.templateID, template: element);
        if (!templateList.contains(template)) templateList.add(template);
      }
    });
    print(templateList.length.toString());
  }

  int tempId = 0;

  Future getProcedureTemplateDetails({required int templateId}) async {
    tempId = templateId;
    hasError = false;
    //_insuranceCardService.clearInsuranceCard();
    setState(ViewState.BusyLocal);
    await _procedureService.getProcedureTemplateDetails(templateId: templateId);
    if (_procedureService.hasError) {
      error = _procedureService.error;
      setState(ViewState.ErrorLocal);
    } else
      setState(ViewState.Idle);
  }

  Future postProcedure(PostProcedureReqModel postProcedureReqModel, int mrn, {bool isLocalBusy = false}) async {
    hasError = false;
    if (isLocalBusy)
      setState(ViewState.BusyLocal);
    else
      setState(ViewState.Busy);
    await _procedureService.postProcedure(postProcedureReqModel);
    if (_procedureService.hasError) {
      error = _procedureService.error;
      setState(ViewState.ErrorLocal);
    } else {
      await getProcedure(mrn: mrn, isLocalBusy: isLocalBusy);
      setState(ViewState.Idle);
    }
  }

  Future validationProcedure(ProcedureValidationRequestModel procedureValidateRequestModel, {bool isLocalBusy = false}) async {
    hasError = false;
    if (isLocalBusy) {
      setState(ViewState.BusyLocal);
    } else {
      setState(ViewState.Busy);
    }
    await _procedureService.validationProcedure(procedureValidateRequestModel);
    if (_procedureService.hasError) {
      error = _procedureService.error;
      setState(ViewState.ErrorLocal);
    } else {
      setState(ViewState.Idle);
    }
  }

  Future updateProcedure({required UpdateProcedureRequestModel updateProcedureRequestModel, int? mrn, bool isLocalBusy = false}) async {
    hasError = false;
    if (isLocalBusy)
      setState(ViewState.BusyLocal);
    else
      setState(ViewState.Busy);
    await _procedureService.updateProcedure(updateProcedureRequestModel);
    if (_procedureService.hasError) {
      error = _procedureService.error;
      setState(ViewState.ErrorLocal);
    } else
      setState(ViewState.Idle);
    //await getProcedure(mrn: mrn);
  }

  void getPatientRadOrders(PatiantInformtion patient, {String? patientType, bool isInPatient = false}) async {
    setState(ViewState.Busy);
    await _radiologyService.getPatientRadOrders(patient, isInPatient: isInPatient);
    _isRadiologyVIDAPlus = _radiologyService.isRadiologyVIDAPlus;
    if (_radiologyService.hasError) {
      error = _radiologyService.error;
      if (patientType == "7")
        setState(ViewState.ErrorLocal);
      else
        setState(ViewState.ErrorLocal);
    } else {
      _radiologyService.finalRadiologyList.forEach((element) {
        List<FinalRadiologyList> finalRadiologyListClinic = _finalRadiologyListClinic.where((elementClinic) => elementClinic.filterName == element.clinicDescription).toList();

        if (finalRadiologyListClinic.length != 0) {
          _finalRadiologyListClinic[finalRadiologyListClinic.indexOf(finalRadiologyListClinic[0])].finalRadiologyList.add(element);
        } else {
          _finalRadiologyListClinic.add(FinalRadiologyList(filterName: element.clinicDescription, finalRadiology: element));
        }

        //   FinalRadiologyList list sort via project
        List<FinalRadiologyList> finalRadiologyListHospital = _finalRadiologyListHospital
            .where(
              (elementClinic) => elementClinic.filterName == element.projectName,
            )
            .toList();

        if (finalRadiologyListHospital.length != 0) {
          _finalRadiologyListHospital[finalRadiologyListHospital.indexOf(finalRadiologyListHospital[0])].finalRadiologyList.add(element);
        } else {
          _finalRadiologyListHospital.add(FinalRadiologyList(filterName: element.projectName, finalRadiology: element));
        }
      });

      setState(ViewState.Idle);
    }
  }

  String get radImageURL => _radiologyService.url;

  getRadImageURL({int? invoiceNo, int lineItem = 0, int projectId = 0, required PatiantInformtion patient}) async {
    setState(ViewState.Busy);
    await _radiologyService.getRadImageURL(invoiceNo: invoiceNo, lineItem: lineItem, projectId: projectId, patient: patient);
    if (_radiologyService.hasError) {
      error = _radiologyService.error;
      setState(ViewState.Error);
    } else
      setState(ViewState.Idle);
  }

  setFilterType(FilterType filterType) {
    this.filterType = filterType;
    notifyListeners();
  }

  List<PatientLabSpecialResult> get patientLabSpecialResult => _labsService.patientLabSpecialResult;

  List<LabResult> get labResultList => _labsService.labResultList;

  List<LabResultList> labResultLists = [];

  List<LabResultList> get labResultListsCoustom {
    return labResultLists;
  }

  void getLabs(PatiantInformtion patient, {bool isInpatient = false}) async {
    setState(ViewState.Busy);
    await _labsService.getPatientLabOrdersList(patient, isInpatient);
    if (_labsService.hasError) {
      error = _labsService.error;
      setState(ViewState.Error);
    } else {
      setState(ViewState.Idle);
    }
  }

  getLaboratoryResult({required String projectID, required int clinicID, required String invoiceNo, required String orderNo, required PatiantInformtion patient}) async {
    setState(ViewState.Busy);
    await _labsService.getLaboratoryResult(invoiceNo: invoiceNo, orderNo: orderNo, projectID: projectID, clinicID: clinicID, patient: patient);
    if (_labsService.hasError) {
      error = _labsService.error;
      setState(ViewState.Error);
    } else {
      setState(ViewState.Idle);
    }
  }

  getPatientLabOrdersResults({PatientLabOrders? patientLabOrder, required String procedure, required PatiantInformtion patient}) async {
    setState(ViewState.Busy);
    await _labsService.getPatientLabOrdersResults(patientLabOrder: patientLabOrder, procedure: procedure, patient: patient);
    if (_labsService.hasError) {
      error = _labsService.error;
      setState(ViewState.Error);
    } else {
      bool isShouldClear = false;
      if (_labsService.labOrdersResultsList.length == 1) {
        labOrdersResultsList.forEach((element) {
          if (element.resultValue!.contains('/') || element.resultValue!.contains('*') || element.resultValue!.isEmpty) isShouldClear = true;
        });
      }
      if (isShouldClear) _labsService.labOrdersResultsList.clear();
      setState(ViewState.Idle);
    }
  }

  sendLabReportEmail({required PatientLabOrders patientLabOrder, required String mes}) async {
    await _labsService.sendLabReportEmail(patientLabOrder: patientLabOrder);
    if (_labsService.hasError) {
      error = _labsService.error;
    } else
      DrAppToastMsg.showSuccesToast(mes);
  }

  Future preparePostProcedure({
    String? remarks,
    String? orderType,
    required PatiantInformtion patient,
    List<cpe.EntityList>? entityList,
    ProcedureType? procedureType,
    bool isLocalBusy = false,
  }) async {
    ///TODO Roaa Move it to function
    if (isLocalBusy) {
      setState(ViewState.BusyLocal);
    } else {
      setState(ViewState.Busy);
    }
    PostProcedureReqModel postProcedureReqModel = new PostProcedureReqModel();
    ProcedureValidationRequestModel procedureValadteRequestModel = new ProcedureValidationRequestModel();
    procedureValadteRequestModel.patientMRN = patient.patientMRN;
    procedureValadteRequestModel.episodeID = patient.episodeNo;
    procedureValadteRequestModel.appointmentNo = patient.appointmentNo;

    List<Procedures> controlsProcedure = [];

    postProcedureReqModel.appointmentNo = patient.appointmentNo;
    postProcedureReqModel.episodeID = patient.episodeNo;
    postProcedureReqModel.patientMRN = patient.patientMRN;

    entityList!.forEach((element) {
      procedureValadteRequestModel.procedure = [element.procedureId!];
      List<Controls> controls = [];
      controls.add(
        Controls(code: "remarks", controlValue: element.remarks != null ? element.remarks : ""),
      );
      controls.add(
        Controls(code: "ordertype", controlValue: procedureType == ProcedureType.PROCEDURE ? element.type ?? "1" : "0"),
      );
      controlsProcedure.add(Procedures(category: element.categoryID, procedure: element.procedureId, controls: controls));
    });

    postProcedureReqModel.procedures = controlsProcedure;
    await validationProcedure(procedureValadteRequestModel, isLocalBusy: isLocalBusy);
    if (state == ViewState.Idle) {
      if (valadteProcedureList[0].entityList!.length == 0) {
        await postProcedure(postProcedureReqModel, patient.patientMRN!, isLocalBusy: isLocalBusy);

        if (state == ViewState.ErrorLocal) {
          Utils.showErrorToast(error);
          getProcedure(mrn: patient.patientMRN!, isLocalBusy: isLocalBusy);
        } else if (state == ViewState.Idle) {
          DrAppToastMsg.showSuccesToast('procedure has been added');
          if (Navigator.canPop(AppGlobal.CONTEX)) Navigator.pop(AppGlobal.CONTEX);
          if (Navigator.canPop(AppGlobal.CONTEX)) Navigator.pop(AppGlobal.CONTEX);
        }
      } else {
        if (state == ViewState.ErrorLocal) {
          Utils.showErrorToast(error);
          getProcedure(mrn: patient.patientMRN!);
        } else if (state == ViewState.Idle) {
          Utils.showErrorToast(valadteProcedureList[0].entityList![0].warringMessages);
        }
      }
    } else {
      Utils.showErrorToast(error);
      Future.delayed(Duration(seconds: 1), () {
        GifLoaderDialogUtils.hideDialog(AppGlobal.CONTEX);
      });
    }
  }

  bool isEntityListSelected(cpe.EntityList masterKey, List<cpe.EntityList> entityList) {
    Iterable<cpe.EntityList> history = entityList.where((element) => masterKey.procedureId == element.procedureId);
    if (history.length > 0) {
      return true;
    }
    return false;
  }

  bool isProcedureEntityListSelected(ProcedureTempleteDetailsModel masterKey, List<ProcedureTempleteDetailsModel> entityList) {
    Iterable<ProcedureTempleteDetailsModel> history = entityList.where((element) => masterKey.templateID == element.templateID && masterKey.procedureName == element.procedureName);
    if (history.length > 0) {
      return true;
    }
    return false;
  }

  Future addProcedures(ProcedureViewModel model, List<ProcedureTempleteDetailsModel> items, PatiantInformtion patient, TextEditingController remarksController, {bool isLocalBusy = false}) async {
    if (isLocalBusy) {
      setState(ViewState.BusyLocal);
    } else {
      setState(ViewState.Busy);
    }
    List<cpe.EntityList> entityList = [];
    items.forEach((element) {
      entityList.add(
        cpe.EntityList(
          procedureId: element.procedureID,
          remarks: element.remarks,
          categoryID: element.categoryID,
          type: element.type,
        ),
      );
    });
    await locator<AnalyticsService>().logEvent(
      eventCategory: "Procedure Checkout Screen",
      eventAction: "Add New Procedure",
    );
    await model.preparePostProcedure(entityList: entityList, patient: patient, remarks: remarksController.text, isLocalBusy: isLocalBusy, procedureType: ProcedureType.PROCEDURE );
  }

  Future filterSearchResults(String query, List<cpe.EntityList> masterList, List<cpe.EntityList> items) async {
    List<cpe.EntityList> dummySearchList = [];
    dummySearchList.addAll(masterList);
    if (query.isNotEmpty) {
      List<cpe.EntityList> dummyListData = [];
      dummySearchList.forEach((item) {
        if (item.procedureName!.toLowerCase().contains(query.toLowerCase())) {
          dummyListData.add(item);
        }
      });
      items.clear();
      items.addAll(dummyListData);
    } else {
      items.clear();
      items.addAll(masterList);
    }
  }

  void filterProcedureSearchResults(String query, List<ProcedureTempleteDetailsModelList> masterList, Function(List<ProcedureTempleteDetailsModelList>) onItemSearched) {
    List<ProcedureTempleteDetailsModelList> dummySearchList = [];
    if (masterList != null) dummySearchList.addAll(masterList);
    if (query.isNotEmpty) {
      List<ProcedureTempleteDetailsModelList> dummyListData = [];
      dummySearchList.forEach((item) {
        if (item.templateName!.toLowerCase().contains(query.toLowerCase())) {
          dummyListData.add(item);
        }
      });
      onItemSearched(dummyListData);
      return;
    } else {
      onItemSearched(dummySearchList);
    }
  }

  Future isPrincipalCovered({required PatiantInformtion patient}) async {
    // setState(ViewState.Busy);
    await _prescriptionService.isPrincipalCovered(patient);
    if (_prescriptionService.hasError) {
      error = _prescriptionService.error;
      setState(ViewState.ErrorLocal);
    } else {
      // setState(ViewState.Idle);
    }
  }
}
