import 'dart:developer';

import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/chat_models/chat_message_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/provider_offers_model.dart';
import 'package:mc_common_app/models/requests_models/request_model.dart';
import 'package:mc_common_app/utils/enums.dart';

abstract class RequestRepo {
  Future<GenericRespModel> createRequest({
    required int requestTypeId,
    required int vehicleTypeId,
    required String brand,
    required String model,
    required String year,
    required bool isNew,
    required int countryID,
    required int cityID,
    required String price,
    required String description,
    required String address,
    required bool isSpecialServiceNeeded,
    required List requestImages,
  });

  Future<List<OffersModel>> getOffersByRequest({required int requestId, int serviceProviderId = 0});

  Future<ProviderOffersModel> getOffersFromProvidersByRequest({required int requestId});

  Future<List<RequestModel>> getRequests({required int providerOrCustomerID});

  Future<List<RequestModel>> getRequestsBasedOnFilters({
    required int requestTypeId,
    int requestStatusId = 0,
    int reqOfferStatus = 0,
    int? cityId = 0,
    int? vehicleYearId = 0,
    String? vehicleModel = "",
    String? vehicleBrand = "",
    String? requestedDate = "",
    int? conditionId = 0,
    int pageIndex = 0,
    int pageSize = 100,
  });

  Future<List<RequestModel>> getServiceRequestsForProviders({required int serviceProviderID});

  Future<GenericRespModel> updateRequestStatus({required RequestStatusEnum requestStatusEnum, required int requestId});

  Future<GenericRespModel> updateRequestOfferStatus({required RequestOfferStatusEnum requestOfferStatusEnum, required int requestOfferId, required String comments});

  Future<GenericRespModel> updateRequestOfferFromProvider({
    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 List requestImages,
    required RequestOfferStatusEnum requestOfferStatusEnum,
  });
}

class RequestRepoImp implements RequestRepo {
  ApiClient apiClient = injector.get<ApiClient>();
  AppState appState = injector.get<AppState>();

  @override
  Future<GenericRespModel> createRequest({
    required int requestTypeId,
    required int vehicleTypeId,
    required String brand,
    required String model,
    required String year,
    required bool isNew,
    required int countryID,
    required int cityID,
    required String price,
    required String description,
    required String address,
    required bool isSpecialServiceNeeded,
    required List requestImages,
  }) async {
    Map<String, dynamic> postParams = {
      "customerID": appState.getUser.data!.userInfo!.customerId ?? 0,
      "requestType": requestTypeId,
      "vehicleTypeID": vehicleTypeId,
      "brand": brand,
      "model": model,
      "year": year,
      "isNew": isNew,
      "countryID": countryID,
      "cityID": cityID,
      "price": price,
      "description": description,
      "address": address,
      "isSpecialServiceNeeded": false,
      "requestImages": requestImages,
    };
    GenericRespModel enumGenericModel = await apiClient.postJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.createRequest,
      postParams,
      token: appState.getUser.data!.accessToken,
    );
    return enumGenericModel;
  }

  @override
  Future<List<RequestModel>> getRequests({required int providerOrCustomerID}) async {
    final paramsForGetRequests = {
      "pageSize": 100,
      "pageIndex": 0,
    };

    if (appState.currentAppType == AppType.provider) {
      paramsForGetRequests.addEntries([MapEntry("providerID", providerOrCustomerID)]);
    } else {
      paramsForGetRequests.addEntries([MapEntry("customerID", providerOrCustomerID)]);
    }
    GenericRespModel enumGenericModel = await apiClient.postJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.getRequest,
      paramsForGetRequests,
      token: appState.getUser.data!.accessToken,
    );
    List<RequestModel> requests = List.generate(
      enumGenericModel.data.length,
      (index) => RequestModel.fromJson(
        enumGenericModel.data[index],
      ),
    );
    return requests;
  }

  @override
  Future<List<RequestModel>> getRequestsBasedOnFilters({
    required int requestTypeId,
    int requestStatusId = 0,
    int reqOfferStatus = 0,
    int? cityId = 0,
    int? vehicleYearId = 0,
    String? vehicleModel = "",
    String? vehicleBrand = "",
    String? requestedDate = "",
    int? conditionId = 0,
    int pageIndex = 0,
    int pageSize = 100,
  }) async {
    final paramsForGetRequests = {
      "pageIndex": pageIndex,
      "pageSize": pageSize,
      "doPagination": true,
      "requestType": requestTypeId.toString(),
      "requestStatus": requestStatusId.toString(),
      "reqOfferStatus": reqOfferStatus.toString(),
      "brand": vehicleBrand.toString(),
      "requestedDate": requestedDate,
      "model": vehicleModel.toString(),
      "year": vehicleYearId.toString(),
      "cityID": cityId.toString(),
      "isNew": conditionId == 0 ? "" : conditionId == 1,
    };

    if (appState.currentAppType == AppType.customer) {
      paramsForGetRequests.addEntries([MapEntry("customerID", appState.getUser.data!.userInfo!.customerId ?? 0)]);
    } else {
      paramsForGetRequests.addEntries([MapEntry("providerID", appState.getUser.data!.userInfo!.providerId.toString())]);
    }

    paramsForGetRequests.removeWhere((key, value) => value == "" || value == "0");

    if (appState.currentAppType == AppType.provider && requestTypeId == 2) {
      List<RequestModel> requests = await getRequestBasedOnFiltersForProvidersServiceRequest(paramsForGetRequests);
      return requests;
    }

    GenericRespModel enumGenericModel = await apiClient.postJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.getRequest,
      paramsForGetRequests,
      token: appState.getUser.data!.accessToken,
    );

    List<RequestModel> requests = List.generate(
      enumGenericModel.data.length,
      (index) => RequestModel.fromJson(enumGenericModel.data[index]),
    );
    return requests;
  }

  Future<List<RequestModel>> getRequestBasedOnFiltersForProvidersServiceRequest(Map<String, Object?> parameters) async {
    List<String> requestStatusList = [
      RequestStatusEnum.submitted.getIdFromRequestStatusEnum().toString(),
      RequestStatusEnum.completed.getIdFromRequestStatusEnum().toString(),
      RequestStatusEnum.inProgress.getIdFromRequestStatusEnum().toString(),
      RequestStatusEnum.paid.getIdFromRequestStatusEnum().toString(),
      RequestStatusEnum.delivery.getIdFromRequestStatusEnum().toString(),
      RequestStatusEnum.shipping.getIdFromRequestStatusEnum().toString(),
    ];

    if (parameters['requestStatus'] != null && parameters['requestStatus'] != "0") {
      parameters.addEntries([
        MapEntry("RequestStatuses", [parameters['requestStatus'].toString()])
      ]);
    } else {
      parameters.removeWhere((key, value) => key == "requestStatus");
      parameters.addEntries([MapEntry("RequestStatuses", requestStatusList)]);
    }

    parameters.removeWhere((key, value) => key == "providerID");
    parameters.removeWhere((key, value) => key == "pageIndex");
    parameters.removeWhere((key, value) => key == "pageSize");
    parameters.removeWhere((key, value) => key == "doPagination");
    parameters.addEntries([MapEntry("ServiceProviderId", appState.getUser.data!.userInfo!.providerId.toString())]);

    log("parameters: ${parameters}");
    // final parameters = {
    //   "ServiceProviderId": serviceProviderID.toString(),
    //   "RequestType": "2", // Only to get the Service Request
    //   "RequestStatuses": requestStatusList,
    // };
    GenericRespModel genericRespModel = await apiClient.getJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.getServiceRequestsForProvider,
      queryParameters: parameters,
      token: appState.getUser.data!.accessToken,
    );
    List<RequestModel> requests = List.generate(
      genericRespModel.data.length,
      (index) => RequestModel.fromJson(
        genericRespModel.data[index],
      ),
    );
    return requests;
  }

  @override
  Future<List<RequestModel>> getServiceRequestsForProviders({required int serviceProviderID}) async {
    List<String> requestStatusList = [
      RequestStatusEnum.submitted.getIdFromRequestStatusEnum().toString(),
      RequestStatusEnum.completed.getIdFromRequestStatusEnum().toString(),
      RequestStatusEnum.inProgress.getIdFromRequestStatusEnum().toString(),
      RequestStatusEnum.paid.getIdFromRequestStatusEnum().toString(),
      RequestStatusEnum.delivery.getIdFromRequestStatusEnum().toString(),
      RequestStatusEnum.shipping.getIdFromRequestStatusEnum().toString(),
    ];
    final parameters = {
      "ServiceProviderId": serviceProviderID.toString(),
      "RequestType": "2", // Only to get the Service Request
      "RequestStatuses": requestStatusList,
    };
    GenericRespModel genericRespModel = await apiClient.getJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.getServiceRequestsForProvider,
      queryParameters: parameters,
      token: appState.getUser.data!.accessToken,
    );
    List<RequestModel> requests = List.generate(
      genericRespModel.data.length,
      (index) => RequestModel.fromJson(
        genericRespModel.data[index],
      ),
    );
    return requests;
  }

  @override
  Future<List<OffersModel>> getOffersByRequest({required int requestId, int serviceProviderId = 0}) async {
    var queryParameters = {
      "RequestID": requestId.toString(),
      "ServiceProviderID": serviceProviderId.toString(),
    };
    GenericRespModel genericRespModel = await apiClient.getJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.getRequestOffers,
      queryParameters: queryParameters,
      token: appState.getUser.data!.accessToken,
    );
    List<OffersModel> offersList = List.generate(
      genericRespModel.data.length,
      (index) => OffersModel.fromJson(genericRespModel.data[index]),
    );
    return offersList;
  }

  @override
  Future<ProviderOffersModel> getOffersFromProvidersByRequest({required int requestId}) async {
    final customerId = appState.getUser.data!.userInfo!.customerId;
    var queryParameters = {
      "customerID": customerId.toString(),
      "requestID": requestId.toString(),
    };
    GenericRespModel genericRespModel = await apiClient.postJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.requestOffersSpsGet,
      queryParameters,
      token: appState.getUser.data!.accessToken,
    );
    ProviderOffersModel providerOffersModel = ProviderOffersModel();
    if (genericRespModel.data != null && genericRespModel.data.length > 0) {
      providerOffersModel = ProviderOffersModel.fromJson(genericRespModel.data.first, requestId);
    }
    return providerOffersModel;
  }

  @override
  Future<GenericRespModel> updateRequestStatus({required RequestStatusEnum requestStatusEnum, required int requestId}) async {
    var queryParameters = {
      "requestId": requestId.toString(),
      "requestStatus": requestStatusEnum.getIdFromRequestStatusEnum().toString(),
    };
    GenericRespModel genericRespModel = await apiClient.postJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      appState.currentAppType == AppType.provider ? ApiConsts.updateRequestProvider : ApiConsts.updateRequestCustomer,
      queryParameters,
      token: appState.getUser.data!.accessToken,
    );

    return genericRespModel;
  }

  @override
  Future<GenericRespModel> updateRequestOfferStatus({required RequestOfferStatusEnum requestOfferStatusEnum, required int requestOfferId, required String comments}) async {
    var queryParameters = {
      "requestOfferId": requestOfferId.toString(),
      "offerStatus": requestOfferStatusEnum.getIdFromRequestOfferStatusEnum().toString(),
      "comments": comments,
    };
    GenericRespModel genericRespModel = await apiClient.postJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.updateRequestOfferStatus,
      queryParameters,
      token: appState.getUser.data!.accessToken,
    );

    return genericRespModel;
  }

  @override
  Future<GenericRespModel> updateRequestOfferFromProvider({
    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 List requestImages,
    required RequestOfferStatusEnum requestOfferStatusEnum,
  }) async {
    final providerId = appState.getUser.data!.userInfo!.providerId;

    var queryParameters = {
      "id": offerId,
      "requestID": requestId,
      "serviceProviderID": providerId,
      "offerStatus": requestOfferStatusEnum.getIdFromRequestOfferStatusEnum(),
      "serviceItem": serviceItemName,
      "comment": message,
      "price": offerPrice,
      "offeredItemCreatedBy": manufacturedById.toString(),
      "offeredItemCreatedOn": manufacturedOn.toString(),
      "reqOfferImages": requestImages,
      "isDeliveryAvailable": isDeliveryAvailable
    };
    GenericRespModel genericRespModel = await apiClient.postJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.updateRequestOffer,
      queryParameters,
      token: appState.getUser.data!.accessToken,
    );

    return genericRespModel;
  }
}
