import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:mypoint_flutter_app/configs/api_paths.dart';
import 'package:mypoint_flutter_app/base/base_response_model.dart';
import 'package:mypoint_flutter_app/configs/constants.dart';
import 'package:mypoint_flutter_app/extensions/string_extension.dart';
import 'package:mypoint_flutter_app/networking/restful_api_client.dart';
import 'package:mypoint_flutter_app/preference/data_preference.dart';
import 'package:mypoint_flutter_app/screen/game/models/game_bundle_response.dart';
import 'package:mypoint_flutter_app/screen/voucher/models/product_model.dart';
import '../configs/callbacks.dart';
import '../configs/device_info.dart';
import '../directional/directional_screen.dart';
import '../model/auth/biometric_register_response_model.dart';
import '../model/auth/login_token_response_model.dart';
import '../model/auth/profile_response_model.dart';
import '../preference/package_info.dart';
import '../screen/health_book/health_book_model.dart';
import '../screen/history_point/models/history_point_models.dart';
import '../screen/history_point/models/transaction_summary_by_date_model.dart';
import '../screen/register_campaign/model/verify_register_model.dart';
import '../screen/splash/models/update_response_model.dart';
import '../preference/point/header_home_model.dart';
import '../screen/affiliate/model/affiliate_brand_model.dart';
import '../screen/affiliate/model/affiliate_category_model.dart';
import '../screen/affiliate/model/affiliate_product_top_sale_model.dart';
import '../screen/affiliate/model/cashback_overview_model.dart';
import '../screen/affiliate_brand_detail/models/affiliate_brand_detail_model.dart';
import '../screen/bank_account_manager/bank_account_info_model.dart';
import '../screen/campaign7day/models/campaign_7day_info_model.dart';
import '../screen/campaign7day/models/campaign_7day_mission_model.dart';
import '../screen/campaign7day/models/campaign_7day_reward_model.dart';
import '../screen/daily_checkin/daily_checkin_models.dart';
import '../screen/data_network_service/product_network_data_model.dart';
import '../screen/device_manager/device_manager_model.dart';
import '../screen/electric_payment/models/customer_contract_object_model.dart';
import '../screen/electric_payment/models/electric_payment_response_model.dart';
import '../screen/faqs/faqs_model.dart';
import '../screen/flash_sale/models/flash_sale_category_model.dart';
import '../screen/flash_sale/models/flash_sale_detail_response.dart';
import '../screen/game/models/game_bundle_item_model.dart';
import '../screen/history_point_cashback/models/history_point_cashback_model.dart';
import '../screen/home/models/achievement_model.dart';
import '../screen/home/models/hover_data_model.dart';
import '../screen/home/models/main_section_config_model.dart';
import '../screen/home/models/my_product_model.dart';
import '../screen/home/models/notification_unread_model.dart';
import '../screen/home/models/pipi_detail_model.dart';
import '../screen/interested_categories/models/interested_categories_model.dart';
import '../screen/invite_friend_campaign/models/invite_friend_campaign_model.dart';
import '../screen/location_address/models/district_address_model.dart';
import '../screen/location_address/models/province_address_model.dart';
import '../screen/membership/models/membership_info_response.dart';
import '../screen/mobile_card/models/mobile_service_redeem_data.dart';
import '../screen/mobile_card/models/product_mobile_card_model.dart';
import '../screen/mobile_card/models/usable_voucher_model.dart';
import '../screen/notification/models/category_notify_item_model.dart';
import '../screen/notification/models/notification_detail_model.dart';
import '../screen/notification/models/notification_list_data_model.dart';
import '../screen/onboarding/model/check_phone_response_model.dart';
import '../screen/onboarding/model/onboarding_info_model.dart';
import '../screen/otp/model/create_otp_response_model.dart';
import '../screen/otp/model/otp_verify_response_model.dart';
import '../screen/pageDetail/model/campaign_detail_model.dart';
import '../screen/pageDetail/model/detail_page_rule_type.dart';
import '../screen/popup_manager/popup_manager_model.dart';
import '../screen/quiz_campaign/quiz_campaign_model.dart';
import '../screen/register_campaign/model/registration_form_package_model.dart';
import '../screen/topup/models/brand_network_model.dart';
import '../screen/traffic_service/traffic_service_model.dart';
import '../screen/transaction/history/transaction_category_model.dart';
import '../screen/transaction/history/transaction_history_model.dart';
import '../screen/transaction/history/transaction_history_response_model.dart';
import '../screen/transaction/model/order_product_payment_response_model.dart';
import '../screen/transaction/model/payment_bank_account_info_model.dart';
import '../screen/transaction/model/payment_method_model.dart';
import '../screen/transaction/model/preview_order_payment_model.dart';
import '../screen/voucher/models/like_product_response_model.dart';
import '../screen/voucher/models/my_mobile_card_response.dart';
import '../screen/voucher/models/my_product_status_type.dart';
import '../screen/voucher/models/product_brand_model.dart';
import '../screen/voucher/models/product_store_model.dart';
import '../screen/voucher/models/product_type.dart';
import '../screen/voucher/models/search_product_response_model.dart';

extension RestfulAPIClientAllRequest on RestfulAPIClient {
  Future<BaseResponseModel<UpdateResponseModel>> checkUpdateApp() async {
    final operatingSystem = Platform.operatingSystem;
    final version = await AppInfoHelper.version;
    final buildNumber = await AppInfoHelper.buildNumber;
    final body = {"operating_system": operatingSystem, "software_model": "MyPoint", "version": version, "build_number": buildNumber};
    return requestNormal(APIPaths.checkUpdate, Method.POST, body, (data) => UpdateResponseModel.fromJson(data as Json));
  }

  Future<BaseResponseModel<OnboardingInfoModel>> getOnboardingInfo() async {
    return requestNormal(
      APIPaths.getOnboardingInfo,
      Method.GET,
      {},
      (data) => OnboardingInfoModel.fromJson(data as Json),
    );
  }

  Future<BaseResponseModel<CheckPhoneResponseModel>> checkPhoneNumber(String phone) async {
    var deviceKey = await DeviceInfo.getDeviceId();
    var key = "$phone+_=$deviceKey/*8854";
    final body = {"device_key": deviceKey, "phone_number": phone, "key": key.toSha256()};
    return requestNormal(
      APIPaths.checkPhoneNumber,
      Method.POST,
      body,
      (data) => CheckPhoneResponseModel.fromJson(data as Json),
    );
  }

  Future<BaseResponseModel<OTPVerifyResponseModel>> verifyOTP(String otp, String mfaToken) async {
    final body = {"otp": otp, "mfaToken": mfaToken};
    return requestNormal(
      APIPaths.verifyOtpWithAction,
      Method.POST,
      body,
      (data) => OTPVerifyResponseModel.fromJson(data as Json),
    );
  }

  Future<BaseResponseModel<OTPResendResponseModel>> resendOTP(String mfaToken) async {
    final body = {"mfaToken": mfaToken};
    return requestNormal(
      APIPaths.retryOtpWithAction,
      Method.POST,
      body,
      (data) => OTPResendResponseModel.fromJson(data as Json),
    );
  }

  Future<BaseResponseModel<CreateOTPResponseModel>> requestOtpDeleteAccount() async {
    return requestNormal(
      APIPaths.otpDeleteAccountRequest,
      Method.POST,
      {},
      (data) => CreateOTPResponseModel.fromJson(data as Json),
    );
  }

  Future<BaseResponseModel<CreateOTPResponseModel>> verifyDeleteAccount(String otp) async {
    return requestNormal(APIPaths.verifyDeleteAccount, Method.POST, {
      "otp": otp,
    }, (data) => CreateOTPResponseModel.fromJson(data as Json));
  }

  Future<BaseResponseModel<EmptyCodable>> signup(String phone, String password) async {
    var deviceKey = await DeviceInfo.getDeviceId();
    final body = {"username": phone, "password": password.toSha256(), "device_key": deviceKey};
    return requestNormal(APIPaths.signup, Method.POST, body, (data) => EmptyCodable.fromJson(data as Json));
  }

  Future<BaseResponseModel<LoginTokenResponseModel>> login(String phone, String password) async {
    var deviceKey = await DeviceInfo.getDeviceId();
    final body = {
      "username": phone,
      "password": password.toSha256(),
      "device_key": deviceKey,
      "workspace_code": "8854",
    };
    return requestNormal(APIPaths.login, Method.POST, body, (data) => LoginTokenResponseModel.fromJson(data as Json));
  }

  Future<BaseResponseModel<EmptyCodable>> logout() async {
    var deviceKey = await DeviceInfo.getDeviceId();
    var phone = DataPreference.instance.phone ?? "";
    final body = {
      "username": phone,
      "device_key": deviceKey,
      "lang": "vi",
    };
    return requestNormal(APIPaths.logout, Method.POST, body, (data) => EmptyCodable.fromJson(data as Json));
  }

  Future<BaseResponseModel<LoginTokenResponseModel>> loginWithBiometric(String phone) async {
    var deviceKey = await DeviceInfo.getDeviceId();
    var bioToken = await DataPreference.instance.getBioToken(phone) ?? "";
    final body = {"username": phone, "bioToken": bioToken, "deviceKey": deviceKey, "workspaceCode": "8854"};
    return requestNormal(
      APIPaths.loginWithBiometric,
      Method.POST,
      body,
      (data) => LoginTokenResponseModel.fromJson(data as Json),
    );
  }

  Future<BaseResponseModel<ProfileResponseModel>> getUserProfile() async {
    return requestNormal(APIPaths.getUserInfo, Method.GET, {}, (data) => ProfileResponseModel.fromJson(data as Json));
  }

  Future<BaseResponseModel<TokenRefreshResponseModel>> refreshToken() async {
    String? token = DataPreference.instance.token ?? "";
    String? refreshToken = DataPreference.instance.refreshToken ?? "";
    final body = {
      "access_token_old": token,
      "refresh_token": refreshToken,
      'lang': 'vi',
    };
    return requestNormal(APIPaths.refreshToken, Method.POST, body, (data) => TokenRefreshResponseModel.fromJson(data as Json));
  }

  Future<BaseResponseModel<CreateOTPResponseModel>> otpCreateNew(String ownerId) async {
    final body = {"owner_id": ownerId, "ttl": Constants.otpTtl, "resend_after_second": Constants.otpTtl, 'lang': 'vi'};
    return requestNormal(
      APIPaths.otpCreateNew,
      Method.POST,
      body,
      (data) => CreateOTPResponseModel.fromJson(data as Json),
    );
  }

  Future<BaseResponseModel<CreateOTPResponseModel>> otpVerifyForDoingNextEvent(
    String ownerId,
    String otp,
    String nextEventName,
  ) async {
    final body = {
      "owner_id": ownerId,
      "otp": otp,
      "next_event_name": nextEventName,
      "ttdne": 180, //  TODO
      "ttl": Constants.otpTtl, "resend_after_second": Constants.otpTtl,
    };
    return requestNormal(
      APIPaths.otpVerifyForDoingNextEvent,
      Method.POST,
      body,
      (data) => CreateOTPResponseModel.fromJson(data as Json),
    );
  }

  Future<BaseResponseModel<CampaignDetailResponseModel>> websitePageGetDetail(String id) async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"website_page_id": id, "access_token": token};
    return requestNormal(
      APIPaths.websitePageGetDetail,
      Method.POST,
      body,
      (data) => CampaignDetailResponseModel.fromJson(data as Json),
    );
  }

  Future<BaseResponseModel<CampaignDetailResponseModel>> websitePage(DetailPageRuleType rule) async {
    final body = {"code": rule.key};
    return requestNormal(
      APIPaths.websitePage,
      Method.GET,
      body,
      (data) => CampaignDetailResponseModel.fromJson(data as Json),
    );
  }

  Future<BaseResponseModel<FAQItemModelResponse>> websiteFolderGetPageList(Json body) async {
    return requestNormal(
      APIPaths.websiteFolderGetPageList,
      Method.POST,
      body,
      (data) => FAQItemModelResponse.fromJson(data as Json),
    );
  }

  Future<BaseResponseModel<EmptyCodable>> accountPasswordReset(String phone, String password) async {
    final body = {"login_name": phone, "password": password.toSha256()};
    return requestNormal(
      APIPaths.accountPasswordReset,
      Method.POST,
      body,
      (data) => EmptyCodable.fromJson(data as Json),
    );
  }

  Future<BaseResponseModel<EmptyCodable>> accountPasswordChange(String phone, String password) async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"login_name": phone, "password": password.toSha256(), "access_token": token};
    return requestNormal(
      APIPaths.accountPasswordChange,
      Method.POST,
      body,
      (data) => EmptyCodable.fromJson(data as Json),
    );
  }

  Future<BaseResponseModel<EmptyCodable>> accountLoginForPasswordChange(String phone, String password) async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"login_name": phone, "password": password.toSha256(), "access_token": token};
    return requestNormal(
      APIPaths.accountLoginForPasswordChange,
      Method.POST,
      body,
      (data) => EmptyCodable.fromJson(data as Json),
    );
  }

  Future<BaseResponseModel<BiometricRegisterResponseModel>> accountBioCredential() async {
    var deviceKey = await DeviceInfo.getDeviceId();
    final body = {"deviceKey": deviceKey};
    return requestNormal(
      APIPaths.bioCredential,
      Method.POST,
      body,
      (data) => BiometricRegisterResponseModel.fromJson(data as Json),
    );
  }

  Future<BaseResponseModel<BiometricRegisterResponseModel>> registerBiometric() async {
    var deviceKey = await DeviceInfo.getDeviceId();
    final body = {"deviceKey": deviceKey};
    return requestNormal(
      APIPaths.registerBiometric,
      Method.POST,
      body,
      (data) => BiometricRegisterResponseModel.fromJson(data as Json),
    );
  }

  Future<BaseResponseModel<EmptyCodable>> unRegisterBiometric() async {
    var deviceKey = await DeviceInfo.getDeviceId();
    final path = "${APIPaths.unRegisterBiometric}/$deviceKey";
    final body = {"deviceKey": deviceKey};
    return requestNormal(path, Method.POST, body, (data) => EmptyCodable.fromJson(data as Json));
  }

  Future<BaseResponseModel<HeaderHomeModel>> getHomeHeaderData() async {
    return requestNormal(APIPaths.headerHome, Method.GET, {}, (data) => HeaderHomeModel.fromJson(data as Json));
  }

  Future<BaseResponseModel<List<ProductModel>>> getProducts(Json body) async {
    return requestNormal(APIPaths.getProducts, Method.GET, body, (data) {
      final list = data as List<dynamic>;
      return list.map((e) => ProductModel.fromJson(e)).toList();
    });
  }

  Future<BaseResponseModel<SearchProductResponseModel>> getSearchProducts(Json body) async {
    return requestNormal(
      APIPaths.getSearchProducts,
      Method.POST,
      body,
      (data) => SearchProductResponseModel.fromJson(data as Json),
    );
  }

  Future<BaseResponseModel<List<ProductModel>>> productsCustomerLikes(Json body) async {
    return requestNormal(APIPaths.productsCustomerLikes, Method.GET, body, (data) {
      final list = data as List<dynamic>;
      return list.map((e) => ProductModel.fromJson(e)).toList();
    });
  }

  Future<BaseResponseModel<ProductModel>> getProduct(int id) async {
    final path = APIPaths.getProductDetail.replaceAll("%@", id.toString());
    return requestNormal(path, Method.GET, {}, (data) => ProductModel.fromJson(data as Json));
  }

  Future<BaseResponseModel<ProductModel>> getCustomerProductDetail(int id) async {
    final path = APIPaths.getCustomerProductDetail.replaceAll("%@", id.toString());
    return requestNormal(path, Method.GET, {}, (data) => ProductModel.fromJson(data as Json));
  }

  Future<BaseResponseModel<List<ProductStoreModel>>> getProductStores(int id) async {
    final body = {"product_id": id, "size": 20, "index": 0};
    return requestNormal(APIPaths.getProductStores, Method.GET, body, (data) {
      final list = data as List<dynamic>;
      return list.map((e) => ProductStoreModel.fromJson(e)).toList();
    });
  }

  Future<BaseResponseModel<LikeProductResponseModel>> likeProduct(int id) async {
    final body = {"product_id": id};
    return requestNormal(APIPaths.productCustomerLikes, Method.POST, body, (data) {
      return LikeProductResponseModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<EmptyCodable>> unlikeProduct(int id) async {
    final path = APIPaths.productCustomerUnlikes.replaceAll("%@", id.toString());
    return requestNormal(path, Method.DELETE, {}, (data) => EmptyCodable.fromJson(data as Json));
  }

  Future<BaseResponseModel<GameBundleResponse>> getGames() async {
    return requestNormal(APIPaths.getGames, Method.GET, {}, (data) {
      return GameBundleResponse.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<List<EmptyCodable>>> verifyOrderProduct(Json body) async {
    return requestNormal(APIPaths.verifyOrderProduct, Method.POST, body, (data) {
      final list = data as List<dynamic>;
      return list.map((e) => EmptyCodable.fromJson(e)).toList();
    });
  }

  Future<BaseResponseModel<GameBundleItemModel>> getGameDetail(String id) async {
    final path = APIPaths.getGameDetail.replaceAll("%@", id);
    return requestNormal(path, Method.POST, {}, (data) {
      return GameBundleItemModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<GameBundleItemModel>> submitGameCard(String gameId, String itemId) async {
    final path = APIPaths.submitGameCard.replaceFirst("%@", gameId).replaceFirst("%@", itemId);
    return requestNormal(path, Method.POST, {}, (data) {
      return GameBundleItemModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<List<AffiliateCategoryModel>>> affiliateCategoryGetList() async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token};
    return requestNormal(APIPaths.affiliateCategoryGetList, Method.POST, body, (data) {
      final list = data as List<dynamic>;
      return list.map((e) => AffiliateCategoryModel.fromJson(e)).toList();
    });
  }

  Future<BaseResponseModel<List<AffiliateBrandModel>>> affiliateBrandGetList({String? categoryCode}) async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token};
    if ((categoryCode ?? '').isNotEmpty) {
      body['category_code'] = categoryCode!;
    }
    return requestNormal(APIPaths.affiliateBrandGetList, Method.POST, body, (data) {
      final list = data as List<dynamic>;
      return list.map((e) => AffiliateBrandModel.fromJson(e)).toList();
    });
  }

  Future<BaseResponseModel<List<AffiliateProductTopSaleModel>>> affiliateProductTopSale() async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token};
    return requestNormal(APIPaths.affiliateProductTopSale, Method.POST, body, (data) {
      final list = data as List<dynamic>;
      return list.map((e) => AffiliateProductTopSaleModel.fromJson(e)).toList();
    });
  }

  Future<BaseResponseModel<CashbackOverviewModel>> getCashBackOverview() async {
    return requestNormal(APIPaths.getCashbackOverview, Method.GET, {}, (data) {
      return CashbackOverviewModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<RegistrationFormPackageModel>> getRegistrationForm(String id) async {
    final path = APIPaths.getRegistrationForm.replaceAll("%@", id);
    return requestNormal(path, Method.GET, {}, (data) {
      return RegistrationFormPackageModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<PreviewOrderPaymentModel>> getPreviewOrderInfo(Json body) async {
    return requestNormal(APIPaths.getPreviewOrderInfo, Method.POST, body, (data) {
      return PreviewOrderPaymentModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<List<PaymentBankAccountInfoModel>>> getPreviewOrderBankAccounts() async {
    return requestNormal(APIPaths.getPreviewOrderBankAccounts, Method.GET, {}, (data) {
      final list = data as List<dynamic>;
      return list.map((e) => PaymentBankAccountInfoModel.fromJson(e)).toList();
    });
  }

  Future<BaseResponseModel<List<PaymentMethodModel>>> getPreviewPaymentMethods() async {
    return requestNormal(APIPaths.getPreviewPaymentMethods, Method.GET, {}, (data) {
      final list = data as List<dynamic>;
      return list.map((e) => PaymentMethodModel.fromJson(e)).toList();
    });
  }

  Future<BaseResponseModel<List<CategoryNotifyItemModel>>> getNotificationCategories() async {
    return requestNormal(APIPaths.getNotificationCategories, Method.GET, {}, (data) {
      final list = data as List<dynamic>;
      return list.map((e) => CategoryNotifyItemModel.fromJson(e)).toList();
    });
  }

  Future<BaseResponseModel<NotificationListDataModel>> getNotifications(Json body) async {
    return requestNormal(APIPaths.getNotifications, Method.POST, body, (data) {
      return NotificationListDataModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<EmptyCodable>> deleteNotification(String id) async {
    return requestNormal(APIPaths.deleteNotification, Method.POST, {"notification_id__": id}, (data) {
      return EmptyCodable.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<EmptyCodable>> deleteAllNotifications() async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token};
    return requestNormal(APIPaths.deleteAllNotifications, Method.POST, body, (data) {
      return EmptyCodable.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<EmptyCodable>> notificationMarkAsSeen() async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token};
    return requestNormal(APIPaths.notificationMarkAsSeen, Method.POST, body, (data) {
      return EmptyCodable.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<NotificationDetailResponseModel>> getNotificationDetail(String id) async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"notification_id": id, "mark_as_seen": "1", "access_token": token};
    return requestNormal(APIPaths.notificationGetDetail, Method.POST, body, (data) {
      return NotificationDetailResponseModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<TransactionHistoryModel>> getTransactionHistoryDetail(String id) async {
    final path = APIPaths.getTransactionHistoryDetail.replaceAll("%@", id);
    return requestNormal(path, Method.GET, {}, (data) {
      return TransactionHistoryModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<OrderProductPaymentResponseModel>> orderSubmitPayment({
    required List<ProductModel> products,
    required int quantity,
    required String requestId,
    int? point,
    int? cash,
    PaymentMethodModel? method,
    int? paymentTokenId,
    bool? saveToken,
    String? metadata,
    String? targetPhoneNumber,
  }) async {
    final items =
        products.map((product) {
          return {
            'product_id': product.id,
            'product_type': product.type ?? '',
            'quantity': quantity,
            'target_phone_number': targetPhoneNumber ?? '',
          };
        }).toList();
    final Map<String, dynamic> params = {'request_id': requestId, 'items': items, 'flow': '21'};
    // flash_sale
    final firstProduct = products.first;
    if (firstProduct.previewFlashSale?.isFlashSalePrice == true && firstProduct.previewFlashSale?.id != null) {
      params['flash_sale_id'] = firstProduct.previewFlashSale!.id;
    }
    // Optional parameters
    if (method != null) {
      params['payment_method'] = method.code;
    }
    if (point != null && point != 0) {
      params['pay_point'] = point;
    }
    if (cash != null && cash != 0) {
      params['pay_cash'] = cash;
    }
    if (paymentTokenId != null) {
      params['payment_token_id'] = paymentTokenId;
    }
    if (saveToken != null) {
      params['save_token'] = saveToken;
    }
    if (metadata != null) {
      params['metadata'] = metadata;
    }
    return requestNormal(APIPaths.orderSubmitPayment, Method.POST, params, (data) {
      return OrderProductPaymentResponseModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<PipiDetailResponseModel>> getPipiDetail() async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token};
    return requestNormal(APIPaths.getPipiDetail, Method.POST, body, (data) {
      return PipiDetailResponseModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<List<MainSectionConfigModel>>> getSectionLayoutHome() async {
    return requestNormal(APIPaths.getSectionLayoutHome, Method.GET, {}, (data) {
      final list = data as List<dynamic>;
      return list.map((e) => MainSectionConfigModel.fromJson(e)).toList();
    });
  }

  Future<BaseResponseModel<AchievementListResponse>> getAchievementList(Json body) async {
    return requestNormal(APIPaths.achievementGetList, Method.POST, body, (data) {
      return AchievementListResponse.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<HoverDataModel>> getDataPiPiHome() async {
    return requestNormal(APIPaths.getIconPiPiHome, Method.GET, {}, (data) {
      return HoverDataModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<NotificationUnreadData>> getNotificationUnread() async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token};
    return requestNormal(APIPaths.getNotificationUnread, Method.POST, body, (data) {
      return NotificationUnreadData.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<HeaderHomeModel>> getDynamicHeaderHome() async {
    return requestNormal(APIPaths.getDynamicHeaderHome, Method.GET, {}, (data) {
      return HeaderHomeModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<List<MyProductModel>>> getCustomerProducts(Json body) async {
    return requestNormal(APIPaths.getCustomerProducts, Method.GET, body, (data) {
      final list = data as List<dynamic>;
      return list.map((e) => MyProductModel.fromJson(e)).toList();
    });
  }

  Future<BaseResponseModel<EmptyCodable>> updateWorkerSiteProfile(Json body) async {
    String? token = DataPreference.instance.token ?? "";
    body["access_token"] = token;
    return requestNormal(APIPaths.updateWorkerSiteProfile, Method.POST, body, (data) {
      return EmptyCodable.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<ProvinceAddressResponse>> locationProvinceGetList() async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token, "country_code2": "VN"};
    return requestNormal(APIPaths.locationProvinceGetList, Method.POST, body, (data) {
      return ProvinceAddressResponse.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<DistrictAddressResponse>> locationDistrictGetList(String provinceCode) async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token, "province_code": provinceCode};
    return requestNormal(APIPaths.locationDistrictGetList, Method.POST, body, (data) {
      return DistrictAddressResponse.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<MembershipInfoResponse>> getMembershipLevelInfo() async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token, "lang": "vi"};
    return requestNormal(APIPaths.getMembershipLevelInfo, Method.POST, body, (data) {
      return MembershipInfoResponse.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<List<ProductBrandModel>>> getTopUpBrands(ProductType type) async {
    final body = {"type": type.value};
    return requestNormal(APIPaths.getTopUpBrands, Method.GET, body, (data) {
      final list = data as List<dynamic>;
      return list.map((e) => ProductBrandModel.fromJson(e)).toList();
    });
  }

  Future<BaseResponseModel<List<ProductBrandModel>>> productTopUpBrands() async {
    final body = {"topup_type": "PRODUCT_MODEL_MOBILE_SERVICE", "page_size": "999", "page_index": 0};
    return requestNormal(APIPaths.productTopUpsBrands, Method.GET, body, (data) {
      final list = data as List<dynamic>;
      return list.map((e) => ProductBrandModel.fromJson(e)).toList();
    });
  }

  // productTopUpsBrands
  Future<BaseResponseModel<BrandNameCheckResponse>> checkMobileNetwork(String phone) async {
    final body = {"phone": phone};
    return requestNormal(APIPaths.checkMobileNetwork, Method.GET, body, (data) {
      return BrandNameCheckResponse.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<ProductMobileCardResponse>> productMobileCardGetList() async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"start": 0, "limit": 200, "access_token": token};
    return requestNormal(APIPaths.productMobileCardGetList, Method.POST, body, (data) {
      return ProductMobileCardResponse.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<MobileServiceRedeemData>> redeemMobileCard(String productId) async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"product_id": productId, "get_customer_balance": "1", "access_token": token};
    return requestNormal(APIPaths.redeemMobileCard, Method.POST, body, (data) {
      return MobileServiceRedeemData.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<RedeemProductResponseModel>> getMobileCardCode(String itemId) async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"product_item_id": itemId, "access_token": token};
    return requestNormal(APIPaths.getMobileCardCode, Method.POST, body, (data) {
      return RedeemProductResponseModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<List<TopUpNetworkDataModel>>> getNetworkProducts(String brandId) async {
    final body = {
      "brand_id": brandId,
      "topup_type": "PRODUCT_MODEL_MOBILE_SERVICE",
      "page_size": "999",
      "page_index": 0,
    };
    return requestNormal(APIPaths.getNetworkProducts, Method.GET, body, (data) {
      final list = data as List<dynamic>;
      return list.map((e) => TopUpNetworkDataModel.fromJson(e)).toList();
    });
  }

  Future<BaseResponseModel<EmptyCodable>> redeemProductTopUps(int productId, String phoneNumber) async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token, "product_id": productId, "quantity": 1, "phone_number": phoneNumber, "lang": "vi"};
    return requestNormal(APIPaths.redeemProductTopUps, Method.POST, body, (data) {
      return EmptyCodable.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<HistoryPointCashBackResponse>> historyPointCashBackRequest(Json body) async {
    String? token = DataPreference.instance.token ?? "";
    body["access_token"] = token;
    return requestNormal(APIPaths.historyCashBackPoint, Method.GET, body, (data) {
      return HistoryPointCashBackResponse.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<AffiliateBrandDetailModel>> getAffiliateBrandDetail(String brandId) async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token, "brand_id": brandId};
    return requestNormal(APIPaths.affiliateBrandGetDetail, Method.POST, body, (data) {
      return AffiliateBrandDetailModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<InviteFriendDetailModel>> getCampaignInviteFriend() async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token};
    return requestNormal(APIPaths.campaignInviteFriend, Method.GET, body, (data) {
      return InviteFriendDetailModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<CampaignInviteFriendDetail>> getDetailCampaignInviteFriend() async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token};
    return requestNormal(APIPaths.inviteFriendCampaigns, Method.GET, body, (data) {
      return CampaignInviteFriendDetail.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<InviteFriendResponse>> phoneInviteFriend(String phone) async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token, 'username': phone};
    return requestNormal(APIPaths.phoneInviteFriend, Method.POST, body, (data) {
      return InviteFriendResponse.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<CheckInDataModel>> rewardOpportunityGetList() async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token, 'number_day': '7'};
    return requestNormal(APIPaths.rewardOpportunityGetList, Method.POST, body, (data) {
      return CheckInDataModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<SubmitCheckInData>> submitCheckIn() async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token};
    return requestNormal(APIPaths.rewardOpportunityOpenRequest, Method.POST, body, (data) {
      return SubmitCheckInData.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<TransactionHistoryResponse>> getTransactionHistoryResponse(Json body) async {
    return requestNormal(APIPaths.getTransactionOrderHistory, Method.GET, body, (data) {
      return TransactionHistoryResponse.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<List<TransactionCategoryModel>>> getTransactionHistoryCategories() async {
    return requestNormal(APIPaths.orderHistoryCategories, Method.GET, {}, (data) {
      final list = data as List<dynamic>;
      return list.map((e) => TransactionCategoryModel.fromJson(e)).toList();
    });
  }

  Future<BaseResponseModel<CustomerContractModel>> customerContractRequestSearch(String maKH) async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token, 'ma_khang': maKH};
    return requestNormal(APIPaths.customerContractRequestSearch, Method.POST, body, (data) {
      return CustomerContractModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<List<CustomerContractModel>>> customerContractSearchHistoryGetList() async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token};
    return requestNormal(APIPaths.customerContractSearchHistoryGetList, Method.POST, body, (data) {
      final list = data as List<dynamic>;
      return list.map((e) => CustomerContractModel.fromJson(e)).toList();
    });
  }

  Future<BaseResponseModel<bool>> customerContractDelete(String maKHs) async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token, 'ma_khang': maKHs};
    return requestNormal(APIPaths.customerContractDelete, Method.POST, body, (data) {
      return data == true;
    });
  }

  Future<BaseResponseModel<HealthBookResponseModel>> getHealthBookCards(Json body) async {
    return requestNormal(APIPaths.getHealthBookCards, Method.GET, body, (data) {
      return HealthBookResponseModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<HealthBookCardItemModel>> getDetailHealthBookCard(String id) async {
    final path = APIPaths.detailHealthBookCardDetail.replaceAll("%@", id);
    return requestNormal(path, Method.GET, {}, (data) {
      return HealthBookCardItemModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<TrafficServiceResponseModel>> getProductVnTraSold(Json body) async {
    return requestNormal(APIPaths.getProductVnTraSold, Method.GET, body, (data) {
      return TrafficServiceResponseModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<TrafficServiceDetailModel>> getDetailMyPackageVnTra(String id) async {
    final path = APIPaths.detailMyPackageVnTra.replaceAll("%@", id);
    return requestNormal(path, Method.GET, {}, (data) {
      return TrafficServiceDetailModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<EmptyCodable>> submitPerformMission(Campaign7DayMissionModel mission, String id) async {
    final path = APIPaths.submitCampaignMission.replaceFirst('%@', id).replaceFirst('%@', mission.id.toString());

    return requestNormal(path, Method.POST, {}, (data) {
      return EmptyCodable.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<List<Campaign7DayRewardModel>>> getCampaignRewards(String id) async {
    final path = APIPaths.getCampaignReward.replaceFirst('%@', id);
    return requestNormal(path, Method.GET, {}, (data) {
      final list = data as List<dynamic>;
      return list.map((e) => Campaign7DayRewardModel.fromJson(e)).toList();
    });
  }

  Future<BaseResponseModel<List<String>>> getCampaignLiveTransactions(String id) async {
    final path = APIPaths.getCampaignLiveTransactions.replaceFirst('%@', id);
    return requestNormal(path, Method.GET, {}, (data) {
      if (data is List) {
        return data.map((e) => e.toString()).toList();
      }
      return <String>[];
    });
  }

  Future<BaseResponseModel<Campaign7DayInfoModel>> getCampaignMissions(String id) async {
    final path = APIPaths.getCampaignMissions.replaceFirst('%@', id);
    return requestNormal(path, Method.GET, {}, (data) {
      return Campaign7DayInfoModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<SurveyCampaignInfoModel>> getCampaignQuizSurvey(String id) async {
    final path = APIPaths.getQuizCampaign.replaceFirst('%@', id);
    return requestNormal(path, Method.GET, {}, (data) {
      return SurveyCampaignInfoModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<QuizCampaignSubmitResponseModel>> quizSubmitCampaign(String id, Json body) async {
    final path = APIPaths.quizSubmitCampaign.replaceFirst('%@', id);
    return requestNormal(path, Method.POST, body, (data) {
      return QuizCampaignSubmitResponseModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<List<FlashSaleCategoryModel>>> getFlashSaleCategories(String groupId) async {
    final path = APIPaths.getFlashSaleGroup.replaceFirst('%@', groupId);
    return requestNormal(path, Method.GET, const {}, (data) {
      if (data is List) {
        return data.whereType<Map<String, dynamic>>().map(FlashSaleCategoryModel.fromJson).toList();
      }
      if (data is Map<String, dynamic>) {
        final categories = data['categories'] ?? data['data'] ?? data['items'];
        if (categories is List) {
          return categories.whereType<Map<String, dynamic>>().map(FlashSaleCategoryModel.fromJson).toList();
        }
        if (data.containsKey('_id')) {
          return [FlashSaleCategoryModel.fromJson(Map<String, dynamic>.from(data))];
        }
      }
      return <FlashSaleCategoryModel>[];
    });
  }

  Future<BaseResponseModel<FlashSaleDetailResponse>> getFlashSaleDetail({
    required String groupId,
    int index = 0,
    int size = 10,
    int? categoryId,
  }) async {
    final path = APIPaths.getFlashSaleDetail.replaceFirst('%@', groupId);
    final params = <String, dynamic>{
      'index': index,
      'size': size,
      if (categoryId != null) 'category_id': categoryId,
    };
    return requestNormal(path, Method.GET, params, (data) {
      if (data is Map<String, dynamic>) {
        return FlashSaleDetailResponse.fromJson(data);
      }
      if (data is List && data.isNotEmpty) {
        final first = data.first;
        if (first is Map<String, dynamic>) {
          return FlashSaleDetailResponse.fromJson(first);
        }
      }
      return FlashSaleDetailResponse(products: <ProductModel>[]);
    });
  }

  Future<BaseResponseModel<DeviceItemModel>> getCurrentDevice() async {
    return requestNormal(APIPaths.getCurrentDevice, Method.GET, {}, (data) {
      return DeviceItemModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<DevicesLogoutListResponse>> getLogoutDevices(Json body) async {
    return requestNormal(APIPaths.getLogoutDevices, Method.GET, body, (data) {
      return DevicesLogoutListResponse.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<String>> deleteDevice(String deviceKey) async {
    final path = APIPaths.deleteDevice.replaceFirst('%@', deviceKey);
    return requestNormal(path, Method.DELETE, {}, (data) => data as String);
  }

  Future<BaseResponseModel<InterestedCategoriesResponse>> categoryTopLevelGetList() async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token, "lang": "vi"};
    return requestNormal(APIPaths.categoryTopLevelGetList, Method.POST, body, (data) {
      return InterestedCategoriesResponse.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<EmptyCodable>> submitCategorySubscribe(String code) async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token, 'category_codes': code};
    return requestNormal(APIPaths.categorySubscribeList, Method.POST, body, (data) {
      return EmptyCodable.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<EmptyCodable>> submitCategoryUnsubscribeList(String code) async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token, 'category_codes': code};
    return requestNormal(APIPaths.categoryUnsubscribeList, Method.POST, body, (data) {
      return EmptyCodable.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<ElectricPaymentResponseModel>> customerEvnPaymentGatewayRequest(
    CustomerContractModel contract,
    String paymentMethod,
  ) async {
    String? token = DataPreference.instance.token ?? "";
    final body = {
      "access_token": token,
      'ma_khang': contract.maKH ?? '',
      'evn_bill_id': contract.idHoaHon ?? '',
      'amount': contract.amount ?? 0,
      'payment_method': paymentMethod,
    };
    return requestNormal(APIPaths.customerEvnPaymentGatewayRequest, Method.POST, body, (data) {
      return ElectricPaymentResponseModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<List<PopupManagerModel>>> getPopupManagerCommonScreen() async {
    String? token = DataPreference.instance.token ?? "";
    final body = {"access_token": token, "lang": "vi"};
    return requestNormal(APIPaths.getPopup, Method.POST, body, (data) {
      final list = data as List<dynamic>;
      return list.map((e) => PopupManagerModel.fromJson(e)).toList();
    });
  }

  Future<BaseResponseModel<MyVoucherResponse>> getMyMobileCards(MyProductStatusType status, Json body) async {
    String? token = DataPreference.instance.token ?? "";
    body["access_token"] = token;
    body["product_model_code"] = "PRODUCT_MODEL_MOBILE_CARD";
    body["list_order"] = "DESC";
    var path = '';
    switch (status) {
      case MyProductStatusType.waiting:
        path = APIPaths.getMyProductGetWaitingList;
      case MyProductStatusType.used:
        path = APIPaths.getMyProductGetUsedList;
      case MyProductStatusType.expired:
        path = APIPaths.getMyProductGetExpiredList;
    }
    return requestNormal(path, Method.POST, body, (data) {
      return MyVoucherResponse.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<List<BankAccountInfoModel>>> getOrderPaymentMyAccounts() async {
    return requestNormal(APIPaths.orderPaymentMyAccounts, Method.GET, {}, (data) {
      final list = data as List<dynamic>;
      return list.map((e) => BankAccountInfoModel.fromJson(e)).toList();
    });
  }

  Future<BaseResponseModel<String>> setDefaultBankAccount(String id, bool isDefault) async {
    final path = APIPaths.bankAccountSetDefault.replaceFirst('%@', id);
    final body = {"is_default": isDefault ? 1 : 0};
    return requestNormal(path, Method.POST, body, (data) => data as String);
  }

  Future<BaseResponseModel<String>> deleteBankAccount(String id) async {
    final path = APIPaths.bankAccountDelete.replaceFirst('%@', id);
    return requestNormal(path, Method.DELETE, {}, (data) => data as String);
  }

  Future<BaseResponseModel<TransactionSummaryByDateModel>> transactionGetSummaryByDate(Json body) async {
    String? token = DataPreference.instance.token ?? "";
    body["access_token"] = token;
    return requestNormal(APIPaths.transactionGetSummaryByDate, Method.POST, body, (data) {
      return TransactionSummaryByDateModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<ListHistoryResponseModel>> transactionHistoryGetList(Json body) async {
    String? token = DataPreference.instance.token ?? "";
    body["access_token"] = token;
    return requestNormal(APIPaths.transactionHistoryGetList, Method.POST, body, (data) {
      return ListHistoryResponseModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<DirectionalScreen>> getDirectionOfflineBrand(String id) async {
    final body = {"bank_account": id};
    return requestNormal(APIPaths.getOfflineBrand, Method.GET, body, (data) {
      return DirectionalScreen.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<EmptyCodable>> pushNotificationDeviceUpdateToken(String token) async {
    var deviceKey = await DeviceInfo.getDeviceId();
    final details = await DeviceInfo.getDetails();
    String? accessToken = DataPreference.instance.token ?? "";
    var body = details.toMap();
    body["access_token"] = accessToken;
    body["push_notification_token"] = token;
    body["device_key"] = deviceKey;
    body["lang"] = 'vi';
    body["software_type"] = "Application";
    body["software_model"] = "MyPoint";
    return requestNormal(APIPaths.pushNotificationDeviceUpdateToken, Method.POST, body, (data) {
      return EmptyCodable.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<EmptyCodable>> myProductMarkAsUsed(String id) async {
    String? accessToken = DataPreference.instance.token ?? "";
    final body = {
      "product_item_id": id,
      "lang": "vi",
      "access_token": accessToken,
    };
    return requestNormal(APIPaths.myProductMarkAsUsed, Method.POST, body, (data) {
      return EmptyCodable.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<EmptyCodable>> myProductMarkAsNotUsedYet(String id) async {
    String? accessToken = DataPreference.instance.token ?? "";
    final body = {
      "product_item_id": id,
      "lang": "vi",
      "access_token": accessToken,
    };
    return requestNormal(APIPaths.myProductMarkAsNotUsedYet, Method.POST, body, (data) {
      return EmptyCodable.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<DirectionalScreen>> getDirectionScreen(String path) async {
    var path_ = path.startsWith('/') ? path : '/$path';
    return requestNormal(path_, Method.GET, {}, (data) {
      return DirectionalScreen.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<EmptyCodable>> submitShareContent(String path) async {
    var path_ = path.startsWith('/') ? path : '/$path';
    return requestNormal(path_, Method.GET, {}, (data) {
      return EmptyCodable.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<VerifyRegisterCampaignModel>> verifyRegisterForm(String path, Json body) async {
    var path_ = path.startsWith('/') ? path : '/$path';
    return requestNormal(path_, Method.POST, body, (data) {
      return VerifyRegisterCampaignModel.fromJson(data as Json);
    });
  }

  Future<BaseResponseModel<SubmitViewVoucherCompletedResponse>> submitCampaignViewVoucherComplete() async {
    return requestNormal(APIPaths.submitCampaignViewVoucherComplete, Method.POST, {}, (data) {
      return SubmitViewVoucherCompletedResponse.fromJson(data as Json);
    });
  }
}
