// ignore_for_file: use_build_context_synchronously, avoid_function_literals_in_foreach_calls

import 'dart:convert';
import 'dart:developer';
import 'dart:io';

import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/models/general_models/enums_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/models/requests_models/offers_model.dart';
import 'package:mc_common_app/models/requests_models/provider_offers_model.dart';
import 'package:mc_common_app/models/requests_models/request_model.dart';
import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/repositories/request_repo.dart';
import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:mc_common_app/view_models/base_view_model.dart';
import 'package:mc_common_app/view_models/chat_view_model.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
import 'package:provider/provider.dart';

class RequestsVM extends BaseVM {
  final CommonAppServices commonServices;
  final CommonRepo commonRepo;
  final RequestRepo requestRepo;

  RequestsVM({required this.commonServices, required this.commonRepo, required this.requestRepo});

  List<RequestModel> myRequests = [];
  List<RequestModel> myFilteredRequests = [];

  List<FilterListModel> requestsTypeFilterOptions = [];

  List<EnumsModel> myRequestsTypeEnum = [];

  List<EnumsModel> vehicleConditionsEnum = [];

  List<EnumsModel> requestStatusesEnum = [];

  RequestModel? currentSelectedRequest;

  void updateCurrentSelectedRequest(RequestModel value) {
    currentSelectedRequest = value;
  }

  ReqOffer? acceptedRequestOffer;

  updateAcceptedReqOffer(ReqOffer value) {
    acceptedRequestOffer = value;
    notifyListeners();
  }

  ServiceProvidersOffers? currentSelectedOffer;

  String? acceptedRequestOfferProviderName;

  updateAcceptedRequestOfferProviderName(String value) {
    acceptedRequestOfferProviderName = value;
    notifyListeners();
  }

  String addressSparePartRequestDelivery = "";
  String additionalAddressSparePartRequestDelivery = "";

  void updateAddressSparePartRequestDelivery(String value) {
    addressSparePartRequestDelivery = value;
    notifyListeners();
  }

  void updateAdditionalAddressSparePartRequestDelivery(String value) {
    additionalAddressSparePartRequestDelivery = value;
    notifyListeners();
  }

  Future<void> getRequests({bool isNeedToRebuild = false}) async {
    if (isNeedToRebuild) setState(ViewState.busy);
    applyFilterOnRequestsVM(requestsTypeEnum: RequestsTypeEnum.specialCarRequest);
    isOfferSent = false;
    setState(ViewState.idle);
  }

  Future<bool> getRequestsBasedOnFilters() async {
    myFilteredRequests.clear();
    setState(ViewState.busy);
    int requestTypeIdApi = requestsTypeFilterOptions.firstWhere((element) => element.isSelected).id;

    int requestCityIdApi = 0;
    if (vehicleCityId.selectedId != -1) {
      requestCityIdApi = vehicleCityId.selectedId;
    }
    int requestConditionIdApi = 0;
    if (vehicleConditionId.selectedId != -1) {
      requestConditionIdApi = vehicleConditionId.selectedId;
    }
    int requestVehicleYearIdApi = 0;
    if (vehicleYearId.selectedId != -1) {
      requestVehicleYearIdApi = vehicleYearId.selectedId;
    }
    int requestStatusIdApi = 0;
    if (requestStatusId.selectedId != -1) {
      requestStatusIdApi = requestStatusId.selectedId;
    }

    try {
      myFilteredRequests = await requestRepo.getRequestsBasedOnFilters(
        requestTypeId: requestTypeIdApi,
        cityId: requestCityIdApi,
        conditionId: requestConditionIdApi,
        vehicleBrand: brandForSearch,
        vehicleModel: modelForSearch,
        vehicleYearId: requestVehicleYearIdApi,
        requestStatusId: requestStatusIdApi,
        requestedDate: requestedDateFilter,
      );
      setState(ViewState.idle);
      return true;
    } catch (e, s) {
      logger.i("e: ${e.toString()}");
      setState(ViewState.idle);
      return false;
    }
  }

  List<RequestModel> providersAcceptedRequestsList = [];
  List<FilterListModel> acceptedRequestsTypeFilterOptions = [];

  Future<List<RequestModel>> getProvidersAcceptedRequests() async {
    setState(ViewState.busy);

    if (acceptedRequestsTypeFilterOptions.isEmpty) {
      for (int i = 0; i < myRequestsTypeEnum.length; i++) {
        acceptedRequestsTypeFilterOptions.add(FilterListModel(title: myRequestsTypeEnum[i].enumValueStr, isSelected: false, id: myRequestsTypeEnum[i].enumValue));
      }
      acceptedRequestsTypeFilterOptions[0].isSelected = true;
    }
    providersAcceptedRequestsList.clear();
    try {
      int requestTypeIdApi = acceptedRequestsTypeFilterOptions.firstWhere((element) => element.isSelected).id;

      providersAcceptedRequestsList = await requestRepo.getRequestsBasedOnFilters(
        requestTypeId: requestTypeIdApi,
        reqOfferStatus: RequestOfferStatusEnum.accepted.getIdFromRequestOfferStatusEnum(),
      );
      setState(ViewState.idle);
      return providersAcceptedRequestsList;
    } catch (e) {
      logger.e(e.toString());
      setState(ViewState.idle);
      return [];
    }
  }

  applyFilterOnProvidersAcceptedRequests({required RequestsTypeEnum requestsTypeEnum}) async {
    if (acceptedRequestsTypeFilterOptions.isEmpty) return;
    for (var value in acceptedRequestsTypeFilterOptions) {
      value.isSelected = false;
    }
    acceptedRequestsTypeFilterOptions[requestsTypeEnum.getIdFromRequestTypeEnum() - 1].isSelected = true; // -1 to match with the index
    await getProvidersAcceptedRequests();
    notifyListeners();
  }

  Future<List<RequestModel>> getServiceRequestsForProviders() async {
    setState(ViewState.busy);
    List<RequestModel> serviceRequestsForProviders = await requestRepo.getServiceRequestsForProviders(serviceProviderID: AppState().getUser.data!.userInfo!.providerId);
    setState(ViewState.idle);
    return serviceRequestsForProviders;
  }

  addChatMessagesInRequestsModel({required ChatMessageModel msg, required int index}) {
    myFilteredRequests[index].chatMessages.add(msg);
    notifyListeners();
  }

  overwriteChatMessagesInRequestsModel({required List<ChatMessageModel> messages, required int index, required BuildContext context}) {
    myFilteredRequests[index].chatMessages.clear();
    myFilteredRequests[index].chatMessages = messages;
    if (myFilteredRequests[index].chatMessages.isNotEmpty) {
      for (var message in myFilteredRequests[index].chatMessages) {
        if (message.chatMessageTypeEnum == ChatMessageTypeEnum.offer) {
          context.read<ChatVM>().updateLatestOfferId(message.reqOfferID ?? 0);
          if (message.reqOffer!.requestOfferStatusEnum == RequestOfferStatusEnum.accepted) {
            updateAcceptedReqOffer(message.reqOffer!);
            updateAcceptedRequestOfferProviderName(message.senderName ?? "");
          }
        }
      }
    }
    notifyListeners();
  }

  applyFilterOnRequestsVM({required RequestsTypeEnum requestsTypeEnum}) async {
    if (requestsTypeFilterOptions.isEmpty) return;
    for (var value in requestsTypeFilterOptions) {
      value.isSelected = false;
    }
    requestsTypeFilterOptions[requestsTypeEnum.getIdFromRequestTypeEnum() - 1].isSelected = true; // -1 to match with the index
    await getRequestsBasedOnFilters();
    isOfferSent = false;
    notifyListeners();
  }

  List<ImageModel> pickedVehicleImages = [];
  String vehicleImageError = "";

  void addImageToPickedVehicleImages(ImageModel imageModel) {
    pickedVehicleImages.add(imageModel);
    notifyListeners();
  }

  void removeImageFromList(String filePath) {
    int index = pickedVehicleImages.indexWhere((element) => element.filePath == filePath);
    if (index == -1) {
      return;
    }
    pickedVehicleImages.removeAt(index);
    notifyListeners();
  }

  void pickMultipleImages() async {
    List<ImageModel> imageModels = [];
    List<File> images = await commonServices.pickMultipleImages();
    for (var element in images) {
      imageModels.add(ImageModel(filePath: element.path, isFromNetwork: false));
    }
    pickedVehicleImages.addAll(imageModels);
    if (pickedVehicleImages.isNotEmpty) vehicleImageError = "";
    notifyListeners();
  }

  bool isFetchingRequestType = false;
  bool isFetchingVehicleType = true;
  bool isFetchingVehicleDetail = false;
  List<VehicleTypeModel> vehicleTypes = [];
  VehicleDetailsModel? vehicleDetails;
  List<VehicleBrandsModel> vehicleBrands = [];
  List<VehicleModel> vehicleModels = [];
  List<VehicleYearModel> vehicleYears = [];
  List<VehicleCountryModel> vehicleCountries = [];
  List<VehicleCityModel> vehicleCities = [];

  // ************ REQUESTS SEARCH FILTER ****************

  Future<void> populateDataForRequestsFilter() async {
    setState(ViewState.busy);
    if (myRequestsTypeEnum.isEmpty) {
      myRequestsTypeEnum = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.requestFilterEnumId);
    }

    if (vehicleConditionsEnum.isEmpty) {
      vehicleConditionsEnum = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.conditionEnumId); // to get the vehicle Condition Enum
    }
    if (requestStatusesEnum.isEmpty) {
      requestStatusesEnum = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.requestStatusesFilterEnumId);
    }

    if (requestsTypeFilterOptions.isEmpty || acceptedRequestsTypeFilterOptions.isEmpty) {
      for (int i = 0; i < myRequestsTypeEnum.length; i++) {
        requestsTypeFilterOptions.add(FilterListModel(title: myRequestsTypeEnum[i].enumValueStr, isSelected: false, id: myRequestsTypeEnum[i].enumValue));
        acceptedRequestsTypeFilterOptions.add(FilterListModel(title: myRequestsTypeEnum[i].enumValueStr, isSelected: false, id: myRequestsTypeEnum[i].enumValue));
      }
    }

    if (vehicleBrands.isEmpty) {
      vehicleBrands = await commonRepo.getVehicleBrands(vehicleTypeId: -1);
    }

    if (vehicleYears.isEmpty) {
      vehicleYears = await commonRepo.getVehicleModelYears(vehicleTypeId: -1);
    }

    if (vehicleCities.isEmpty) {
      vehicleCities = await commonRepo.getVehicleCities(countryId: -1); // fetch all the cities
    }
    setState(ViewState.idle);
  }

  ifAlreadyExist({required List<DropValue> list, required DropValue value}) {
    int index = list.indexWhere((element) {
      return element.id == value.id;
    });

    if (index != -1) {
      return true;
    }

    return false;
  }

  String requestedDateFilter = "";

  void updateRequestedDate(String v) {
    if (v.isNotEmpty) {
      updateRequestsFiltersCounter(requestsFiltersCounter + 1);
    } else {
      updateRequestsFiltersCounter(requestsFiltersCounter - 1);
    }

    requestedDateFilter = v;
    notifyListeners();
  }

  SelectionModel requestTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");

  void updateSelectionRequestTypeId(SelectionModel id, {bool isForSearch = false, bool shouldCallVehicleTypes = true, bool showSelectionInDropValue = true}) async {
    if (isForSearch) {
      EnumsModel requestEnum = myRequestsTypeEnum.firstWhere((element) => element.id == id.selectedId);
      DropValue cityValue = DropValue(requestEnum.id, requestEnum.enumValueStr, "");
      if (!ifAlreadyExist(list: requestTypeSearchHistory, value: cityValue)) {
        addToRequestTypeSearchHistory(value: cityValue);
      }
    }
    if (showSelectionInDropValue) {
      requestTypeId = id;
    }
    if (shouldCallVehicleTypes) {
      getVehicleTypes();
    }
    notifyListeners();
  }

  SelectionModel requestStatusId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");

  void updateRequestStatusId(SelectionModel id, {bool isForSearch = false, bool showSelectionInDropValue = true}) async {
    if (isForSearch) {
      EnumsModel requestStatues = requestStatusesEnum.firstWhere((element) => element.enumValue == id.selectedId);
      DropValue cityValue = DropValue(requestStatues.id, requestStatues.enumValueStr, "");
      if (!ifAlreadyExist(list: requestStatusesSearchHistory, value: cityValue)) {
        addToRequestStatusesSearchHistory(value: cityValue);
      }
    }
    if (showSelectionInDropValue) {
      requestStatusId = id;
    }
    notifyListeners();
  }

  //BRANDS
  List<DropValue> vehicleBrandsSearchHistory = [];

  void removeVehicleBrandsAdSearchHistory({bool isClear = false, required int index}) {
    if (isClear) {
      vehicleBrandsSearchHistory.clear();
      notifyListeners();
      return;
    }
    vehicleBrandsSearchHistory.removeAt(index);
    if (vehicleBrandsSearchHistory.isEmpty) {
      updateRequestsFiltersCounter(requestsFiltersCounter - 1);
    }
    notifyListeners();
  }

  void addToVehicleBrandsAdSearchHistory({required DropValue value}) {
    if (vehicleBrandsSearchHistory.isEmpty) {
      updateRequestsFiltersCounter(requestsFiltersCounter + 1);
    }
    vehicleBrandsSearchHistory.add(value);
    notifyListeners();
  } //BRANDS

  List<DropValue> requestStatusesSearchHistory = [];

  void removeRequestStatusesSearchHistory({bool isClear = false, required int index}) {
    if (isClear) {
      requestStatusesSearchHistory.clear();
      notifyListeners();
      return;
    }
    requestStatusesSearchHistory.removeAt(index);
    if (requestStatusesSearchHistory.isEmpty) {
      updateRequestsFiltersCounter(requestsFiltersCounter - 1);
    }
    notifyListeners();
  }

  void addToRequestStatusesSearchHistory({required DropValue value}) {
    if (requestStatusesSearchHistory.isEmpty) {
      updateRequestsFiltersCounter(requestsFiltersCounter + 1);
    }
    requestStatusesSearchHistory.add(value);
    notifyListeners();
  }

  // REQUEST TYPE

  List<DropValue> requestTypeSearchHistory = [];

  void removeRequestTypeSearchHistory({bool isClear = false, required int index}) {
    if (isClear) {
      requestTypeSearchHistory.clear();
      notifyListeners();
      return;
    }
    requestTypeSearchHistory.removeAt(index);
    if (requestTypeSearchHistory.isEmpty) {
      updateRequestsFiltersCounter(requestsFiltersCounter - 1);
    }
    notifyListeners();
  }

  void addToRequestTypeSearchHistory({required DropValue value}) {
    if (requestTypeSearchHistory.isEmpty) {
      updateRequestsFiltersCounter(requestsFiltersCounter + 1);
    }
    requestTypeSearchHistory.add(value);
    notifyListeners();
  }

  // LOCATION
  List<DropValue> vehicleLocationSearchHistory = [];

  void removeVehicleLocationAdSearchHistory({bool isClear = false, required int index}) {
    if (isClear) {
      vehicleLocationSearchHistory.clear();
      notifyListeners();
      return;
    }
    vehicleLocationSearchHistory.removeAt(index);
    if (vehicleLocationSearchHistory.isEmpty) {
      updateRequestsFiltersCounter(requestsFiltersCounter - 1);
    }
    notifyListeners();
  }

  void addToVehicleLocationAdSearchHistory({required DropValue value}) {
    if (vehicleLocationSearchHistory.isEmpty) {
      updateRequestsFiltersCounter(requestsFiltersCounter + 1);
    }
    vehicleLocationSearchHistory.add(value);
    notifyListeners();
  }

  // OWNER
  SelectionModel vehicleConditionId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");

  void updateSelectionVehicleConditionId(SelectionModel id, {bool isForSearch = false, bool showSelectionInDropValue = true}) {
    if (isForSearch) {
      EnumsModel owner = vehicleConditionsEnum.firstWhere((element) => element.enumValue == id.selectedId);
      DropValue ownerValue = DropValue(owner.enumValue, owner.enumValueStr, "");
      if (!ifAlreadyExist(list: vehicleConditionSearchHistory, value: ownerValue)) {
        addToVehicleConditionSearchHistory(value: ownerValue);
      }
    }
    if (showSelectionInDropValue) {
      vehicleConditionId = id;
    }
    notifyListeners();
  }

  List<DropValue> vehicleConditionSearchHistory = [];

  void removeVehicleConditionSearchHistory({bool isClear = false, required int index}) {
    if (isClear) {
      vehicleConditionSearchHistory.clear();
      notifyListeners();
      return;
    }
    vehicleConditionSearchHistory.removeAt(index);
    if (vehicleConditionSearchHistory.isEmpty) {
      updateRequestsFiltersCounter(requestsFiltersCounter - 1);
    }
    notifyListeners();
  }

  void addToVehicleConditionSearchHistory({required DropValue value}) {
    if (vehicleConditionSearchHistory.isEmpty) {
      updateRequestsFiltersCounter(requestsFiltersCounter + 1);
    }
    vehicleConditionSearchHistory.add(value);
    notifyListeners();
  }

  // YEAR
  List<DropValue> vehicleYearSearchHistory = [];

  void removeVehicleYearAdSearchHistory({bool isClear = false, required int index}) {
    if (isClear) {
      vehicleYearSearchHistory.clear();
      notifyListeners();
      return;
    }
    vehicleYearSearchHistory.removeAt(index);
    if (vehicleYearSearchHistory.isEmpty) {
      updateRequestsFiltersCounter(requestsFiltersCounter - 1);
    }
    notifyListeners();
  }

  void addToVehicleYearAdSearchHistory({required DropValue value}) {
    if (vehicleYearSearchHistory.isEmpty) {
      updateRequestsFiltersCounter(requestsFiltersCounter + 1);
    }
    vehicleYearSearchHistory.add(value);
    notifyListeners();
  }

  int requestsFiltersCounter = 0;

  updateRequestsFiltersCounter(int value) {
    requestsFiltersCounter = value;
    notifyListeners();
  }

  SelectionModel vehicleBrandId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");

  void updateSelectionVehicleBrandId(SelectionModel id, {bool isForSearch = false, bool showSelectionInDropValue = true}) {
    if (isForSearch) {
      VehicleBrandsModel brand = vehicleBrands.firstWhere((element) => element.id == id.selectedId);
      DropValue brandValue = DropValue(brand.id ?? 0, brand.vehicleBrandDescription ?? "", "");
      if (!ifAlreadyExist(list: vehicleBrandsSearchHistory, value: brandValue)) {
        addToVehicleBrandsAdSearchHistory(value: brandValue);
      }
    }
    if (showSelectionInDropValue) {
      vehicleBrandId = id;
    }
    vehicleModelId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    vehicleYearId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    notifyListeners();
  }

  SelectionModel vehicleModelId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");

  void updateSelectionVehicleModelId(SelectionModel id) {
    vehicleModelId = id;
    vehicleYearId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    notifyListeners();
  }

  SelectionModel vehicleYearId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");

  void updateSelectionVehicleYearId(SelectionModel id, {bool isForSearch = false, bool shouldSelectionInDropValue = true}) {
    if (isForSearch) {
      VehicleYearModel year = vehicleYears.firstWhere((element) => element.id == id.selectedId);
      DropValue yearValue = DropValue(year.id ?? 0, year.modelYear ?? "", "");
      if (!ifAlreadyExist(list: vehicleYearSearchHistory, value: yearValue)) {
        addToVehicleYearAdSearchHistory(value: yearValue);
      }
    }
    if (shouldSelectionInDropValue) {
      vehicleYearId = id;
    }
    notifyListeners();
  }

  SelectionModel vehicleCountryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");

  void updateSelectionVehicleCountryId(SelectionModel id) async {
    vehicleCountryId = id;
    isCountryFetching = true;
    notifyListeners();
    vehicleCities = await commonRepo.getVehicleCities(countryId: vehicleCountryId.selectedId);
    isCountryFetching = false;
    notifyListeners();
  }

  SelectionModel vehicleCityId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");

  void updateSelectionVehicleCityId(SelectionModel id, {bool isForSearch = false, bool shouldSelectionInDropValue = true}) async {
    if (isForSearch) {
      VehicleCityModel city = vehicleCities.firstWhere((element) => element.id == id.selectedId);
      DropValue cityValue = DropValue(city.id ?? 0, city.cityName ?? "", "");
      if (!ifAlreadyExist(list: vehicleLocationSearchHistory, value: cityValue)) {
        addToVehicleLocationAdSearchHistory(value: cityValue);
      }
    }
    if (shouldSelectionInDropValue) {
      vehicleCityId = id;
    }
    notifyListeners();
  }

  void clearRequestsFilters() {
    clearRequestFilterSelections();
    vehicleBrandsSearchHistory.clear();
    vehicleConditionSearchHistory.clear();
    vehicleLocationSearchHistory.clear();
    vehicleYearSearchHistory.clear();
    requestStatusesSearchHistory.clear();
    requestsFiltersCounter = 0;
    notifyListeners();
  }

  void clearRequestFilterSelections() {
    requestedDateFilter = '';
    vehicleCityId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    vehicleYearId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    vehicleConditionId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    requestStatusId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    brandForSearch = "";
    modelForSearch = "";
  }

  SelectionModel vehicleTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");

  Future<void> getVehicleTypes() async {
    isFetchingVehicleType = true;
    vehicleTypes = await commonRepo.getVehicleTypes();
    isFetchingVehicleType = false;
    notifyListeners();
  }

  resetRequestCreationForm() {
    requestTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    vehicleTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    vehicleBrandId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    vehicleModelId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    vehicleYearId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    vehicleCountryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    vehicleCityId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    vehicleConditionId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    pickedVehicleImages.clear();
    price = '1.0';
    model = "";
    brand = "";
    description = '';
    address = '';
  }

  void updateSelectionVehicleTypeId(SelectionModel id) async {
    vehicleTypeId = id;
    getVehicleBrandsByVehicleTypeId();
    notifyListeners();
  }

  Future<void> getVehicleBrandsByVehicleTypeId() async {
    // if (vehicleBrandId.selectedId == -1) {
    //   return;
    // }
    isFetchingVehicleDetail = true;
    notifyListeners();
    vehicleDetails = await commonRepo.getVehicleDetails(vehicleTypeId: vehicleTypeId.selectedId);

    if (vehicleDetails != null) {
      vehicleBrands = vehicleDetails!.vehicleBrands!;
      vehicleModels = vehicleDetails!.vehicleModels!;
      vehicleYears = vehicleDetails!.vehicleModelYears!;
      vehicleCountries = vehicleDetails!.vehicleCountries!;
      vehicleConditionsEnum = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.conditionEnumId);
    }
    isFetchingVehicleDetail = false;
    notifyListeners();
  }

  bool shippingEnabled = false;

  void updateShippingEnabled(bool v) {
    shippingEnabled = v;
    notifyListeners();
  }

  bool isCountryFetching = false;

  //Request Management
  String price = "1.0";
  String description = "";
  String address = "";
  String model = "";
  String brand = "";

  String modelForSearch = "";
  String brandForSearch = "";

  void updatePrice(String v) {
    price = v;
  }

  void updateDescription(String v) {
    description = v;
  }

  void updateAddress(String v) {
    address = v;
  }

  void updateModel(String v) {
    model = v;
  }

  void updateBrand(String v) {
    brand = v;
  }

  void updateModelForSearch(String v) {
    if (v.isNotEmpty) {
      updateRequestsFiltersCounter(requestsFiltersCounter + 1);
    } else {
      updateRequestsFiltersCounter(requestsFiltersCounter - 1);
    }
    modelForSearch = v;
  }

  void updateBrandForSearch(String v) {
    if (v.isNotEmpty) {
      updateRequestsFiltersCounter(requestsFiltersCounter + 1);
    } else {
      updateRequestsFiltersCounter(requestsFiltersCounter - 1);
    }
    brandForSearch = v;
  }

  Future<RequestPostingImages> convertFileToRequestPostingImages({required ImageModel imageModel}) async {
    RequestPostingImages vehiclePostingImages;
    log("imageModelxx: ${imageModel.isFromNetwork}");
    if (imageModel.isFromNetwork == true) {
      vehiclePostingImages = RequestPostingImages(id: imageModel.id, requestImage: imageModel.filePath);
    } else {
      File file = File(imageModel.filePath!);
      List<int> imageBytes = await file.readAsBytes();
      String image = base64Encode(imageBytes);
      vehiclePostingImages = RequestPostingImages(requestImage: image);
    }
    return vehiclePostingImages;
  }

  Future<List<RequestPostingImages>> getVehiclePostingImageList() async {
    List<RequestPostingImages> requestImages = [];

    for (var image in pickedVehicleImages) {
      var value = await convertFileToRequestPostingImages(imageModel: image);
      requestImages.add(value);
    }

    return requestImages;
  }

  Future<void> onCreateRequestTapped(BuildContext context) async {
    if (validateCreateRequestForm()) {
      Utils.showLoading(context);

      List<RequestPostingImages> vehicleImages = await getVehiclePostingImageList();
      List requestImages = [];
      vehicleImages.forEach((element) {
        requestImages.add(element.toJson());
      });

      // try {
      GenericRespModel respModel = await requestRepo.createRequest(
        requestTypeId: requestTypeId.selectedId,
        vehicleTypeId: vehicleTypeId.selectedId,
        brand: brand,
        model: model,
        year: vehicleYearId.selectedOption,
        isNew: vehicleConditionId.selectedId == 1,
        // 1 for new, 2 for Used
        countryID: vehicleCountryId.selectedId,
        cityID: vehicleCityId.selectedId,
        price: price.isEmpty ? "1.0" : price,
        description: description,
        address: address,
        isSpecialServiceNeeded: false,
        requestImages: requestImages,
      );
      Utils.hideLoading(context);
      if (respModel.messageStatus == 1) {
        Utils.showToast(LocaleKeys.requestSuccessfullyCreated.tr());
        Navigator.pop(context);
        await applyFilterOnRequestsVM(requestsTypeEnum: requestTypeId.selectedId.toRequestTypeEnum());
        resetRequestCreationForm();
      } else {
        Utils.showToast(respModel.message.toString());
      }
      // } catch (e, s) {
      //   Utils.hideLoading(context);
      //   log(e.toString());
      //   Utils.showToast(e.toString());
      // }
    }
  }

  bool validateCreateRequestForm() {
    bool isValid = true;
    if (requestTypeId.selectedId == -1) {
      Utils.showToast(LocaleKeys.selectValidRequestType.tr());
      isValid = false;
    } else if (vehicleTypeId.selectedId == -1) {
      Utils.showToast(LocaleKeys.vehicle_selectValidVehicleType.tr());
      isValid = false;
    } else if (vehicleCountryId.selectedId == -1) {
      Utils.showToast(LocaleKeys.selectValidCountry.tr());
      isValid = false;
    } else if (vehicleCityId.selectedId == -1) {
      Utils.showToast(LocaleKeys.selectValidCity.tr());
      isValid = false;
    } else if (description.isEmpty) {
      Utils.showToast(LocaleKeys.addValidDescription.tr());
      isValid = false;
    } else if (address.isEmpty && requestTypeId.selectedId == 2) {
      Utils.showToast(LocaleKeys.addValidDescription.tr());
      isValid = false;
    }
    return isValid;
  }

  Future<List<OffersModel>> getOffersByRequest({required int requestId, required BuildContext context}) async {
    try {
      Utils.showLoading(context);
      List<OffersModel> respModel = await requestRepo.getOffersByRequest(requestId: requestId);
      Utils.hideLoading(context);
      return respModel;
    } catch (e) {
      Utils.showToast(e.toString());
      Utils.hideLoading(context);
      return [];
    }
  }

  String offerPriceError = "";
  String offerDescriptionError = "";

  String offerPrice = "";

  void updateOfferPrice(String value) {
    offerPrice = value;
    if (value.isNotEmpty) {
      offerPriceError = "";
    }
  }

  String itemManufacturer = "";

  void updateItemManufacturer(String value) {
    itemManufacturer = value;
  }

  String serviceItem = "";

  void updateServiceItem(String value) {
    serviceItem = value;
  }

  bool isDeliveryAvailableStatus = false;

  void updateIsDeliveryAvailableStatus(bool value) {
    isDeliveryAvailableStatus = value;
    notifyListeners();
  }

  String serviceItemCreatedOn = "";

  void updateServiceItemCreatedOn(String value) {
    serviceItemCreatedOn = value;
    notifyListeners();
  }

  String offerDescription = "";

  void updateOfferDescription(String value) {
    offerDescription = value;
    if (value.isNotEmpty || value.length <= 5) {
      offerDescriptionError = "";
    }
  }

  List<OfferRequestCommentModel> providerDeliveryActionsList = [
    OfferRequestCommentModel(
      index: 0,
      isSelected: false,
      title: LocaleKeys.shipping.tr(),
    ),
    OfferRequestCommentModel(
      index: 1,
      isSelected: true,
      title: LocaleKeys.delivery.tr(),
    ),
  ];

  OfferRequestCommentModel selectedProviderDeliveryAction = OfferRequestCommentModel(
    index: 1,
    isSelected: true,
    title: LocaleKeys.delivery.tr(),
  );

  void updateSelectedProviderDeliveryAction(int index) {
    for (var value in providerDeliveryActionsList) {
      value.isSelected = false;
    }
    selectedProviderDeliveryAction = providerDeliveryActionsList[index];
    providerDeliveryActionsList[index].isSelected = true;
    notifyListeners();
  }

  Future<bool> onActionRequestTapped({required BuildContext context, required RequestStatusEnum requestStatusEnum, required int requestId, bool needLoading = true}) async {
    if (needLoading) {
      Utils.showLoading(context);
    }
    try {
      GenericRespModel genericRespModel = await requestRepo.updateRequestStatus(requestStatusEnum: requestStatusEnum, requestId: requestId);
      Utils.showToast(genericRespModel.message.toString());
      if (needLoading) {
        Utils.hideLoading(context);
      }
      return genericRespModel.messageStatus == 1;
    } catch (e) {
      logger.i(e.toString());
      // Utils.showToast(e.toString());
      if (needLoading) {
        Utils.hideLoading(context);
      }
      return false;
    }
  }

  //SENDING OFFER
  bool isSendOfferValidated() {
    bool isValidated = true;
    if (offerPrice.isEmpty) {
      offerPriceError = GlobalConsts.demandAmountError;
      isValidated = false;
      notifyListeners();
    } else {
      offerPriceError = "";
    }

    if (offerDescription.isEmpty) {
      offerDescriptionError = GlobalConsts.descriptionError;
      isValidated = false;
      notifyListeners();
    } else {
      offerDescriptionError = "";
    }
    notifyListeners();

    return isValidated;
  }

  void resetSendOfferBottomSheet() {
    offerPrice = "";
    offerDescription = "";
    offerDescriptionError = "";
    serviceItem = "";
    serviceItemCreatedOn = "";
    itemManufacturer = "";
    isDeliveryAvailableStatus = false;
    pickedVehicleImages.clear();
    notifyListeners();
  }

  bool isBase64String(String input) {
    // This regex checks if the string is a valid Base64 string
    final base64Regex = RegExp(r'^[A-Za-z0-9+/=]+$');

    // Check if the string matches the Base64 pattern
    return base64Regex.hasMatch(input) && (input.length % 4 == 0);
  }

  MessageImageModel convertFileToMessageImageModel({required ImageModel imageModel, required int offerId}) {
    MessageImageModel offerImages;

    if (imageModel.isFromNetwork ?? false) {
      offerImages = MessageImageModel(
        id: imageModel.id,
        imageStr: imageModel.filePath,
        isFromNetwork: true,
        reqOfferID: offerId,
      );
    } else {
      File? file;
      List<int> imageBytes = [];
      String image = '';
      if (!isBase64String(imageModel.filePath!)) {
        file = File(imageModel.filePath!);
        imageBytes = file.readAsBytesSync();
        image = base64Encode(imageBytes);
      } else {
        image = imageModel.filePath!;
      }

      offerImages = MessageImageModel(
        id: 0,
        imageStr: image,
        isFromNetwork: false,
        reqOfferID: offerId,
        imagePath: file?.path,
      );
    }

    return offerImages;
  }

  List<MessageImageModel> getMessagesImageList({required int offerId}) {
    List<MessageImageModel> requestImages = [];
    for (var image in pickedVehicleImages) {
      var value = convertFileToMessageImageModel(imageModel: image, offerId: offerId);
      requestImages.add(value);
    }
    return requestImages;
  }

  bool isOfferSent = false;

  updateIsOfferSent(var value) {
    isOfferSent = value;
    notifyListeners();
  }

  Future<void> updateOfferFromProvider({
    required String message,
    required int requestId,
    required int offerId,
    required String offerPrice,
    required bool isDeliveryAvailable,
    required String serviceItemName,
    required int manufacturedById,
    required String manufacturedOn,
    required int receiverId,
    required int customerRequestIndex,
    required BuildContext context,
  }) async {
    try {
      if (isSendOfferValidated()) {
        Utils.showLoading(context);

        List<MessageImageModel> images = getMessagesImageList(offerId: offerId);
        List offerImages = [];
        images.forEach((element) {
          offerImages.add(element.toJson());
        });
        GenericRespModel genericRespModel = await requestRepo.updateRequestOfferFromProvider(
          message: message,
          requestId: requestId,
          offerId: offerId,
          offerPrice: offerPrice,
          isDeliveryAvailable: isDeliveryAvailable,
          serviceItemName: serviceItemName,
          manufacturedById: manufacturedById,
          manufacturedOn: manufacturedOn,
          requestImages: offerImages,
          requestOfferStatusEnum: RequestOfferStatusEnum.offer,
        );

        Utils.hideLoading(context);

        if (genericRespModel.messageStatus == 1) {
          Utils.showToast(genericRespModel.message ?? "");
          final chatVM = context.read<ChatVM>();

          await chatVM.getRequestsChatMessagesForProvider(
            context: context,
            customerId: receiverId,
            requestOfferId: 0,
            // to get all the messages
            requestId: requestId,
            customerRequestIndex: customerRequestIndex,
          );
          resetSendOfferBottomSheet();
          pop(context);
        }
      }
    } catch (e, s) {
      Utils.hideLoading(context);
      log(e.toString());
      Utils.showToast(e.toString());
    }
  }

  Future<void> onSendOfferPressed({
    required BuildContext context,
    required String receiverId,
    required String message,
    required int requestId,
    required String offerPrice,
    required String serviceItemName,
    required int manufacturedById,
    required String manufacturedOn,
    required RequestModel requestModel,
    required bool isDeliveryAvailable,
    required int requestIndex,
    required bool isFromChatScreen,
    required int? offerId,
  }) async {
    if (isSendOfferValidated()) {
      final chatVM = context.read<ChatVM>();
      List<MessageImageModel> images = getMessagesImageList(offerId: context.read<ChatVM>().latestOfferId);
      List offerImages = [];
      images.forEach((element) {
        offerImages.add(element.toJson());
      });

      bool status = await chatVM.onOfferSendForRequest(
        receiverId: receiverId,
        chatMessageType: ChatMessageTypeEnum.offer,
        message: message,
        requestId: requestId,
        offerPrice: offerPrice,
        isDeliveryAvailable: isDeliveryAvailable,
        manufacturedById: manufacturedById,
        manufacturedOn: manufacturedOn,
        serviceItemName: serviceItemName,
        offerImages: offerImages,
        context: context,
      );
      log("status from onOfferSendForRequest: $status");

      if (!status) {
        Utils.showToast(LocaleKeys.somethingWrong.tr());
        return;
      }

      updateIsOfferSent(true);

      final senderName = AppState().getUser.data!.userInfo!.firstName;
      final senderId = AppState().getUser.data!.userInfo!.userId;
      resetSendOfferBottomSheet();
      Navigator.pop(context);
      ChatMessageModel chatMessageModel = ChatMessageModel(
        isMyMessage: true,
        chatText: message,
        messageType: ChatMessageTypeEnum.offer.getIdFromChatMessageTypeEnum(),
        senderName: senderName,
        senderUserID: senderId,
        receiverUserID: receiverId,
        chatMessageTypeEnum: ChatMessageTypeEnum.offer,
        requestID: requestModel.id,
        offerStatus: RequestOfferStatusEnum.offer.getIdFromRequestOfferStatusEnum(),
        reqOffer: ReqOffer(
          offerStatus: RequestOfferStatusEnum.offer.getIdFromRequestOfferStatusEnum(),
          requestID: requestModel.id,
          price: double.parse(offerPrice),
          isDeliveryAvailable: isDeliveryAvailable,
          manufacturedById: manufacturedById,
          manufacturedOn: manufacturedOn,
          serviceItemName: serviceItemName,
          requestOfferStatusEnum: RequestOfferStatusEnum.offer,
          comment: message,
          offerStatusText: "",
          reqOfferImages: images,
        ),
      );
      context.read<ChatVM>().onNewMessageReceivedForRequestOffer(messages: [chatMessageModel], requestsVM: this, isMyOwnOffer: true);

      if (!isFromChatScreen) {
        ChatViewArgumentsForRequest chatViewArgumentsForRequest = ChatViewArgumentsForRequest(
          chatTypeEnum: ChatTypeEnum.requestOffer,
          requestId: requestModel.id,
          receiverId: requestModel.customerID,
          senderId: senderId ?? "",
          requestIndex: requestIndex,
          providerIndex: -1,
          requestModel: requestModel,
        );

        ChatViewArguments chatViewArguments = ChatViewArguments(chatTypeEnum: ChatTypeEnum.requestOffer, chatViewArgumentsForRequest: chatViewArgumentsForRequest);
        navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments);
      }
    }
  }
}
