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/models/advertisment_models/ad_details_model.dart';
import 'package:mc_common_app/models/advertisment_models/ads_bank_details_model.dart';
import 'package:mc_common_app/models/advertisment_models/ads_duration_model.dart';
import 'package:mc_common_app/models/advertisment_models/pdf_receipt_model.dart';
import 'package:mc_common_app/models/advertisment_models/reserved_ads_models.dart';
import 'package:mc_common_app/models/advertisment_models/special_service_model.dart';
import 'package:mc_common_app/models/chat_models/buyers_chat_for_ads_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/utils/enums.dart';

abstract class AdsRepo {
  Future<List<AdsDurationModel>> getAdsDuration({required int? countryId});

  Future<List<SpecialServiceModel>> getSpecialServices({required int specialServiceType});

  Future<GenericRespModel> createOrUpdateAd({required AdsCreationPayloadModel adsCreationPayloadModel, required bool isCreateNew});

  Future<List<AdDetailsModel>> getAllAds({required bool isMyAds, AdPostStatus? adPostStatus, CreatedByRoleEnum? createdByRoleEnum});

  Future<List<AdDetailsModel>> getExploreAdsBasedOnFilters({
    List<String>? cityIdsList,
    List<String>? vehicleModelYearIdsList,
    List<String>? vehicleBrandIdsList,
    List<String>? createdByRolesIdsList,
    List<String>? vehicleAdConditionIdsList,
    List<String>? vehicleAdCreatedDateList,
  });

  Future<List<AdDetailsModel>> getMyReservedAds();

  Future<List<AdDetailsModel>> getMyAds();

  Future<AdsBankDetailsModel?> getAdBankingAccountInfo({required int adId});

  Future<GenericRespModel> updateAdStatus({required int adId, required AdPostStatus adStatusToUpdate, String? comment});

  Future<GenericRespModel> createAppointmentForAdSpecialService({required int adId, required int photoOfficeID, required int photoOfficeSlotID, required int adsSpecialServiceID});

  Future<GenericRespModel> deleteAd({required int adId});

  Future<GenericRespModel> cancelMyAdReservation({required int adId, required int adsReserveStatus, required String reason});

  Future<GenericRespModel> createReserveAd({required int adId});

  Future<GenericRespModel> uploadBankReceiptsOnReserveDealDone({required int adId, required String detailNote, required List<PdfReceiptModel> pdfReceiptsList});

  Future<List<BuyersChatForAdsModel>> getChatBuyersForAds({required int adsID});

  Future<GenericRespModel> createAdExtensionOrder({required int adID, required List<int> specialServiceIds, required int adsDurationId});
}

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

  @override
  Future<List<AdsDurationModel>> getAdsDuration({required int? countryId}) async {
    int roleID = appState.getUser!.data!.userInfo!.roleId ?? 0;
    var param = {
      "CountryID": countryId.toString() ?? "0",
      "roleID": roleID.toString() ?? "0",
    };
    GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
      token: appState.getUser.data!.accessToken,
      (json) => GenericRespModel.fromJson(json),
      queryParameters: param,
      ApiConsts.vehicleAdsDurationGet,
    );
    List<AdsDurationModel> vehicleAdsDuration = List.generate(adsGenericModel.data.length, (index) => AdsDurationModel.fromJson(adsGenericModel.data[index]));
    return vehicleAdsDuration;
  }

  @override
  Future<List<SpecialServiceModel>> getSpecialServices({required int specialServiceType}) async {
    var params = {
      "SpecialServiceType": specialServiceType.toString(),
    };
    GenericRespModel adsGenericModel =
        await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleAdsSpecialServicesGet, queryParameters: params);
    List<SpecialServiceModel> vehicleAdsDuration = List.generate(adsGenericModel.data.length, (index) => SpecialServiceModel.fromJson(adsGenericModel.data[index]));
    return vehicleAdsDuration;
  }

  @override
  Future<GenericRespModel> createOrUpdateAd({required AdsCreationPayloadModel adsCreationPayloadModel, required bool isCreateNew}) async {
    List vehiclePostingImages = [];

    log("adsCreationPayloadModel.ads!.adsDurationID,: ${adsCreationPayloadModel.ads!.adsDurationID}");
    adsCreationPayloadModel.vehiclePosting!.vehiclePostingImages?.forEach((element) {
      var imageMap = {
        "id": element.id ?? 0,
        "imageName": element.imageName,
        "imageUrl": element.imageUrl,
        "imageStr": element.imageStr,
        "vehiclePostingID": element.vehiclePostingID ?? 0,
        "vehiclePosting": null,
      };
      vehiclePostingImages.add(imageMap);
    });

    List vehiclePostingDamageParts = [];
    adsCreationPayloadModel.vehiclePosting!.vehiclePostingDamageParts?.forEach((element) {
      log("comment: ${element.comment}");
      var imageMap = {
        "id": element.id ?? 0,
        "comment": element.comment,
        "vehicleImageBase64": element.vehicleImageBase64,
        "vehicleDamagePartID": element.vehicleDamagePartID,
        "vehiclePostingID": element.vehiclePostingID ?? 0,
        "isActive": true
      };
      vehiclePostingDamageParts.add(imageMap);
    });
    var postParams = {
      "ads": {
        "id": adsCreationPayloadModel.ads!.id ?? 0,
        "adsDurationID": adsCreationPayloadModel.ads!.adsDurationID,
        "startDate": adsCreationPayloadModel.ads!.startDate,
        "countryId": adsCreationPayloadModel.ads!.countryId,
        "specialServiceIDs": adsCreationPayloadModel.ads!.specialServiceIDs,
        "isMCHandled": false
      },
      "vehiclePosting": {
        "id": adsCreationPayloadModel.vehiclePosting!.id ?? 0,
        "userID": adsCreationPayloadModel.vehiclePosting!.userID,
        "vehicleType": adsCreationPayloadModel.vehiclePosting!.vehicleType,
        "vehicleModelID": adsCreationPayloadModel.vehiclePosting!.vehicleModelID,
        "vehicleModelYearID": adsCreationPayloadModel.vehiclePosting!.vehicleModelYearID,
        "vehicleColorID": adsCreationPayloadModel.vehiclePosting!.vehicleColorID,
        "vehicleCategoryID": adsCreationPayloadModel.vehiclePosting!.vehicleCategoryID,
        "vehicleConditionID": adsCreationPayloadModel.vehiclePosting!.vehicleConditionID,
        "vehicleMileageID": adsCreationPayloadModel.vehiclePosting!.vehicleMileageID,
        "vehicleTransmissionID": adsCreationPayloadModel.vehiclePosting!.vehicleTransmissionID,
        "vehicleSellerTypeID": adsCreationPayloadModel.vehiclePosting!.vehicleSellerTypeID,
        "cityID": adsCreationPayloadModel.vehiclePosting!.cityID,
        "price": adsCreationPayloadModel.vehiclePosting!.price,
        "vehicleVIN": adsCreationPayloadModel.vehiclePosting!.vehicleVIN,
        "vehicleDescription": adsCreationPayloadModel.vehiclePosting!.vehicleDescription,
        "vehicleTitle": adsCreationPayloadModel.vehiclePosting!.vehicleTitle,
        "vehicleDescriptionN": adsCreationPayloadModel.vehiclePosting!.vehicleDescription,
        "isFinanceAvailable": adsCreationPayloadModel.vehiclePosting!.isFinanceAvailable,
        "warantyYears": adsCreationPayloadModel.vehiclePosting!.warantyYears,
        "demandAmount": adsCreationPayloadModel.vehiclePosting!.demandAmount,
        // "adStatus": 1,
        "vehiclePostingImages": vehiclePostingImages,
        "vehiclePostingDamageParts": vehiclePostingDamageParts,
        "mobileNo": adsCreationPayloadModel.vehiclePosting!.phoneNo,
        "whatsAppNo": adsCreationPayloadModel.vehiclePosting!.whatsAppNo,
      }
    };

    String token = appState.getUser.data!.accessToken ?? "";
    GenericRespModel adsGenericModel = await apiClient.postJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      isCreateNew ? ApiConsts.vehicleAdsSingleStepCreate : ApiConsts.vehicleAdsSingleStepUpdate,
      postParams,
      token: token,
    );

    return Future.value(adsGenericModel);
  }

  @override
  Future<List<AdDetailsModel>> getAllAds({required isMyAds, AdPostStatus? adPostStatus, CreatedByRoleEnum? createdByRoleEnum}) async {
    Map<String, dynamic> onlyMyAdsParams = {
      "userID": appState.getUser.data!.userInfo!.userId ?? "",
    };
    if (isMyAds && adPostStatus != null) {
      onlyMyAdsParams.addAll({
        "AdsStatuses": ["${adPostStatus.getIdFromAdPostStatusEnum()}"],
        "PageSize": "30",
      });
    }
    var allAdsParams = {
      "AdsStatuses": ["${AdPostStatus.active.getIdFromAdPostStatusEnum()}"], //only Active ADS
      "isActive": "true", //only Active ADS
      "isExplore": "true",
      "PageSize": "30",
    };

    if (!isMyAds && createdByRoleEnum != null) {
      allAdsParams.addAll({
        "CreatedByRoles": ["${createdByRoleEnum.getIdFromCreatedByRoleEnum()}"],
      });
    }
    GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
      token: appState.getUser.data!.accessToken,
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.vehicleAdsGet,
      queryParameters: isMyAds ? onlyMyAdsParams : allAdsParams,
    );
    List<AdDetailsModel> vehicleAdsDetails = List.generate(adsGenericModel.data.length, (index) => AdDetailsModel.fromJson(adsGenericModel.data[index], isMyAds));
    return vehicleAdsDetails;
  }

  @override
  Future<List<AdDetailsModel>> getExploreAdsBasedOnFilters({
    List<String>? cityIdsList,
    List<String>? vehicleModelYearIdsList,
    List<String>? vehicleBrandIdsList,
    List<String>? createdByRolesIdsList,
    List<String>? vehicleAdConditionIdsList,
    List<String>? vehicleAdCreatedDateList,
  }) async {
    var parameters = {
      "CityIDs": cityIdsList ?? [],
      "VehicleBrandIDs": vehicleBrandIdsList ?? [],
      "VehicleModelYearIDs": vehicleModelYearIdsList ?? [],
      "CreatedByRoles": createdByRolesIdsList ?? [],
      "AdsStatuses": ["${AdPostStatus.active.getIdFromAdPostStatusEnum()}"], //only Active ADS
      "VehicleNew": vehicleAdConditionIdsList ?? [],
      "CreatedOn": (vehicleAdCreatedDateList != null && vehicleAdCreatedDateList.isNotEmpty) ? vehicleAdCreatedDateList.first.toString() : "",
      "isActive": "true", //only Active ADS
      "isExplore": "true",
      "PageSize": "30",
    };

    GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
      token: appState.getUser.data!.accessToken,
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.vehicleAdsGet,
      queryParameters: parameters,
    );
    List<AdDetailsModel> vehicleAdsDetails = List.generate(adsGenericModel.data.length, (index) => AdDetailsModel.fromJson(adsGenericModel.data[index], false));
    return vehicleAdsDetails;
  }

  @override
  Future<List<AdDetailsModel>> getMyReservedAds() async {
    var params = {
      "userID": appState.getUser.data!.userInfo!.userId ?? "",
    };

    GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
      token: appState.getUser.data!.accessToken,
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.myAdsReserveGet,
      queryParameters: params,
    );
    List<MyReservedAdsRespModel> reservedAds = List.generate(adsGenericModel.data.length, (index) => MyReservedAdsRespModel.fromJson(adsGenericModel.data[index]));
    List<String> selectedIdsString = reservedAds.map((component) => component.adsID.toString()).toList();

    if (selectedIdsString.isEmpty) {
      return [];
    }

    return await getAdsPerSpecificIds(ids: selectedIdsString, reservedAds: reservedAds);
  }

  Future<List<AdDetailsModel>> getAdsPerSpecificIds({required List<String> ids, required List<MyReservedAdsRespModel> reservedAds}) async {
    var params = {
      "AdsIDs": ids,
      "isActive": "true",
      "PageSize": "30",
    };
    GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
      token: appState.getUser.data!.accessToken,
      (json) => GenericRespModel.fromJson(json),
      queryParameters: params,
      ApiConsts.vehicleAdsGet,
    );
    List<AdDetailsModel> vehicleAdsDetails = List.generate(adsGenericModel.data.length, (index) => AdDetailsModel.fromJson(adsGenericModel.data[index], true));

    for (int i = 0; i < vehicleAdsDetails.length; i++) {
      vehicleAdsDetails[i].adReserveStatus = (reservedAds[i].adsReserveStatus ?? 0).toAdRserveStatusEnum();
    }

    vehicleAdsDetails.removeWhere((element) => element.adReserveStatus != AdReserveStatus.reserved);
    return vehicleAdsDetails;
  }

  @override
  Future<List<AdDetailsModel>> getMyAds() async {
    var params = {
      "userID": appState.getUser.data!.userInfo!.userId ?? "",
      "PageSize": "30",
    };
    GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
      token: appState.getUser.data!.accessToken,
      (json) => GenericRespModel.fromJson(json),
      queryParameters: params,
      ApiConsts.vehicleAdsGet,
    );
    List<AdDetailsModel> vehicleAdsDetails = List.generate(adsGenericModel.data.length, (index) => AdDetailsModel.fromJson(adsGenericModel.data[index], true));
    return vehicleAdsDetails;
  }

  @override
  Future<AdsBankDetailsModel?> getAdBankingAccountInfo({required int adId}) async {
    var params = {
      "userID": appState.getUser.data!.userInfo!.userId ?? "",
      "AdsID": "$adId",
    };
    GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
      token: appState.getUser.data!.accessToken,
      (json) => GenericRespModel.fromJson(json),
      queryParameters: params,
      ApiConsts.adsMCBankAccountAdGet,
    );

    List<AdsBankDetailsModel> adsBankDetails = List.generate(adsGenericModel.data.length, (index) => AdsBankDetailsModel.fromJson(adsGenericModel.data[index]));
    if (adsBankDetails.isNotEmpty) {
      return adsBankDetails.first;
    }
    return null;
  }

  @override
  Future<GenericRespModel> updateAdStatus({required int adId, required AdPostStatus adStatusToUpdate, String? comment}) async {
    var postParams = {
      "id": adId,
      "status": adStatusToUpdate.getIdFromAdPostStatusEnum().toString(),
      "comment": comment ?? "",
    };

    String token = appState.getUser.data!.accessToken ?? "";
    GenericRespModel adsGenericModel = await apiClient.postJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.adsUpdateStatus,
      postParams,
      token: token,
    );

    return Future.value(adsGenericModel);
  }

  @override
  Future<GenericRespModel> createAdExtensionOrder({required int adID, required List<int> specialServiceIds, required int adsDurationId}) async {
    var postParams = {
      "adsID": adID,
      "adsDurationID": adsDurationId,
      "specialServiceIDs": specialServiceIds,
    };

    String token = appState.getUser.data!.accessToken ?? "";
    GenericRespModel adsGenericModel = await apiClient.postJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.adsExtendDurationCreate,
      postParams,
      token: token,
    );

    return Future.value(adsGenericModel);
  }

  @override
  Future<GenericRespModel> deleteAd({required int adId}) async {
    var postParams = {
      "adID": adId,
    };

    String token = appState.getUser.data!.accessToken ?? "";
    GenericRespModel adsGenericModel = await apiClient.postJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.deleteAd,
      postParams,
      token: token,
    );

    return Future.value(adsGenericModel);
  }

  @override
  Future<GenericRespModel> cancelMyAdReservation({required int adId, required int adsReserveStatus, required String reason}) async {
    int customerID = AppState().getUser.data!.userInfo!.customerId ?? 0;

    var postParams = {
      "adsID": adId,
      "customerID": customerID,
      "adsReserveStatus": adsReserveStatus,
      "comment": reason,
    };

    String token = appState.getUser.data!.accessToken ?? "";
    GenericRespModel adsGenericModel = await apiClient.postJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.deleteAd,
      postParams,
      token: token,
    );

    return Future.value(adsGenericModel);
  }

  @override
  Future<GenericRespModel> createReserveAd({required int adId}) async {
    int customerID = AppState().getUser.data!.userInfo!.customerId ?? 0;

    var postParams = {
      "adsID": adId,
      "customerID": customerID,
      "adsReserveStatus": 0,
    };

    String token = appState.getUser.data!.accessToken ?? "";
    GenericRespModel adsGenericModel = await apiClient.postJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.adsReserveCreate,
      postParams,
      token: token,
    );

    return Future.value(adsGenericModel);
  }

  @override
  Future<GenericRespModel> createAppointmentForAdSpecialService({
    required int adId,
    required int photoOfficeID,
    required int photoOfficeSlotID,
    required int adsSpecialServiceID,
  }) async {
    int customerId = AppState().getUser.data!.userInfo!.customerId ?? 0;

    var postParams = {
      "adsID": adId,
      "photoOfficeID": photoOfficeID,
      "photoOfficeSlotID": photoOfficeSlotID,
      "adsSpecialServiceID": adsSpecialServiceID,
      "customerID": customerId,
    };

    String token = appState.getUser.data!.accessToken ?? "";
    GenericRespModel adsGenericModel = await apiClient.postJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.adsPhotoOfficeAppointmentCreate,
      postParams,
      token: token,
    );

    return Future.value(adsGenericModel);
  }

  @override
  Future<GenericRespModel> uploadBankReceiptsOnReserveDealDone({required int adId, required String detailNote, required List<PdfReceiptModel> pdfReceiptsList}) async {
    int customerId = AppState().getUser.data!.userInfo!.customerId ?? 0;

    List receiptImages = [];

    for (var element in pdfReceiptsList) {
      var pdfReceiptMap = {
        "id": 0,
        "imageName": element.pdfName,
        "imageStr": element.pdfString,
      };
      receiptImages.add(pdfReceiptMap);
    }

    var postParams = {
      "adsID": adId,
      "customerID": customerId,
      "detailNote": detailNote,
      "receiptImages": receiptImages,
    };

    String token = appState.getUser.data!.accessToken ?? "";
    GenericRespModel adsGenericModel = await apiClient.postJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.adsPhotoOfficeAppointmentCreate,
      postParams,
      token: token,
    );

    return Future.value(adsGenericModel);
  }

  @override
  Future<List<BuyersChatForAdsModel>> getChatBuyersForAds({required int adsID}) async {
    var queryParameters = {"AdsID": adsID.toString()};
    GenericRespModel genericRespModel = await apiClient.getJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.getChatBuyersForAds,
      queryParameters: queryParameters,
      token: appState.getUser.data!.accessToken,
    );
    List<BuyersChatForAdsModel> buyersChatListForAds = [];
    if (genericRespModel.data != null && genericRespModel.data.length > 0) {
      buyersChatListForAds = List.generate(genericRespModel.data.length, (index) => BuyersChatForAdsModel.fromJson(genericRespModel.data[index]));
    }
    return buyersChatListForAds;
  }
}
