// ignore_for_file: use_build_context_synchronously, avoid_function_literals_in_foreach_calls

import 'dart:convert';
import 'dart:developer';
import 'dart:io';
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/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/requests_models/offers_model.dart';
import 'package:mc_common_app/models/requests_models/request_model.dart';
import 'package:mc_common_app/models/general_models/widgets_models.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:provider/provider.dart';
import 'package:easy_localization/easy_localization.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 = [];

  RequestModel? currentSelectedRequest;

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

  populateRequestsFilterList() async {
    if (requestsTypeFilterOptions.isNotEmpty) return;

    if (myRequestsTypeEnum.isEmpty) {
      myRequestsTypeEnum = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.requestFilterEnumId);
    }
    for (int i = 0; i < myRequestsTypeEnum.length; i++) {
      requestsTypeFilterOptions.add(FilterListModel(title: myRequestsTypeEnum[i].enumValueStr, isSelected: false, id: myRequestsTypeEnum[i].enumValue));
    }

    notifyListeners();
  }

  Future<void> getRequests({bool isNeedToRebuild = false, required AppType appType}) async {
    if (isNeedToRebuild) setState(ViewState.busy);

    var paramsForGetRequests = <String, dynamic>{};

    paramsForGetRequests = {
      "pageSize": 100,
      "pageIndex": 0,
      // "requestType": 0,
    };
    if (appType == AppType.provider) {
      paramsForGetRequests.addEntries([MapEntry("providerID", AppState().getUser.data!.userInfo!.providerId)]);
    } else {
      paramsForGetRequests.addEntries([MapEntry("customerID", AppState().getUser.data!.userInfo!.customerId)]);
    }
    myRequests = await requestRepo.getRequests(paramsForGetRequests);
    applyFilterOnRequestsVM(requestsTypeEnum: RequestsTypeEnum.specialCarRequest);
    setState(ViewState.idle);
    notifyListeners();
  }

  addChatMessagesInRequestsModel({required ChatMessageModel msg, required int index}) {
    log("msg: $msg");
    log("index: $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);
        }
      }
    }
    notifyListeners();
  }

  applyFilterOnRequestsVM({required RequestsTypeEnum requestsTypeEnum}) {
    if (requestsTypeFilterOptions.isEmpty) return;
    for (var value in requestsTypeFilterOptions) {
      value.isSelected = false;
    }
    requestsTypeFilterOptions[requestsTypeEnum.getIdFromRequestTypeStatusEnum() - 1].isSelected = true; // -1 to match with the index
    myFilteredRequests = myRequests.where((element) => element.requestType == requestsTypeEnum.getIdFromRequestTypeStatusEnum()).toList();
    notifyListeners();
  }

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

  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> vehicleModelYears = [];
  List<VehicleCountryModel> vehicleCountries = [];
  List<VehicleCityModel> vehicleCities = [];

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

  void updateSelectionRequestTypeId(SelectionModel id) async {
    requestTypeId = id;
    getVehicleTypes();
    notifyListeners();
  }

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

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

  resetRequestCreationForm() {
    vehicleTypeId.selectedId = -1;
    vehicleBrandId.selectedId = -1;
    vehicleModelId.selectedId = -1;
    vehicleModelYearId.selectedId = -1;
    vehicleCountryId.selectedId = -1;
    vehicleCityId.selectedId = -1;
  }

  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!;
      vehicleModelYears = vehicleDetails!.vehicleModelYears!;
      vehicleCountries = vehicleDetails!.vehicleCountries!;
    }
    isFetchingVehicleDetail = false;
    notifyListeners();
  }

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

  void updateSelectionVehicleBrandId(SelectionModel id) {
    vehicleBrandId = id;
    vehicleModelId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    vehicleModelYearId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    notifyListeners();
  }

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

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

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

  void updateSelectionVehicleModelYearId(SelectionModel id) {
    vehicleModelYearId = id;
    notifyListeners();
  }

  bool isShippingDeliveryEnabled = false;

  void updateShippingDeliverEnabled(bool v) {
    isShippingDeliveryEnabled = v;
    notifyListeners();
  }

  bool isCountryFetching = false;
  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) {
    vehicleCityId = id;
    notifyListeners();
  }

  //Request Management
  String price = "", description = "";

  updatePrice(String v) {
    price = v;
  }

  updateDescription(String v) {
    description = v;
  }

  Future<RequestPostingImages> convertFileToRequestPostingImages({required File file}) async {
    List<int> imageBytes = await file.readAsBytes();
    String image = base64Encode(imageBytes);
    RequestPostingImages vehiclePostingImages = RequestPostingImages(requestImage: image);
    return vehiclePostingImages;
  }

  Future<List<RequestPostingImages>> getVehiclePostingImageList() async {
    List<RequestPostingImages> requestImages = [];
    log("requestImages: ${pickedVehicleImages.length}");

    for (var image in pickedVehicleImages) {
      var value = await convertFileToRequestPostingImages(file: File(image.filePath!));
      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());
      });
      Map<String, dynamic> body = {
        "customerID": AppState().getUser.data!.userInfo!.customerId ?? 0,
        "requestType": requestTypeId.selectedId,
        "vehicleTypeID": vehicleTypeId.selectedId,
        "brand": vehicleBrandId.selectedOption,
        "model": vehicleModelId.selectedOption,
        "year": vehicleModelYearId.selectedOption,
        "isNew": true,
        "countryID": vehicleCountryId.selectedId,
        "cityID": vehicleCityId.selectedId,
        "price": price,
        "description": description,
        "isSpecialServiceNeeded": false,
        "requestImages": requestImages,
      };
      try {
        GenericRespModel respModel = await requestRepo.createRequest(body);
        Utils.hideLoading(context);
        if (respModel.messageStatus == 1) {
          Utils.showToast(LocaleKeys.requestSuccessfullyCreated.tr());
          Navigator.pop(context);
          await getRequests(appType: AppType.customer);
        } else {
          Utils.showToast(respModel.message.toString());
        }
      } catch (e, s) {
        Utils.hideLoading(context);
        log(s.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 (vehicleBrandId.selectedId == -1) {
      Utils.showToast(LocaleKeys.selectValidBrand.tr());
      isValid = false;
    } else if (vehicleModelId.selectedId == -1) {
      Utils.showToast(LocaleKeys.selectValidModel.tr());
      isValid = false;
    } else if (vehicleModelYearId.selectedId == -1) {
      Utils.showToast(LocaleKeys.selectValidYear.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 (price.isEmpty) {
      Utils.showToast(LocaleKeys.addValidPrice.tr());
      isValid = false;
    } else if (description.isEmpty) {
      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 offerDescription = "";

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

  //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 = "";
    offerDescription = "";
    notifyListeners();
  }

  Future<void> onSendOfferPressed({
    required BuildContext context,
    required String receiverId,
    required String message,
    required int requestId,
    required String offerPrice,
    required RequestModel requestModel,
    required int requestIndex,
    required bool isFromChatScreen,
  }) async {
    if (isSendOfferValidated()) {
      final chatVM = context.read<ChatVM>();
      bool status = await chatVM.onOfferSendForRequest(
        receiverId: receiverId,
        chatMessageType: ChatMessageTypeEnum.offer,
        message: message,
        requestId: requestId,
        offerPrice: offerPrice,
        context: context,
      );

      if (status) {
        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),
              requestOfferStatusEnum: RequestOfferStatusEnum.offer,
              comment: message,
              offerStatusText: "",
            ));
        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,
          );

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