import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';
import 'package:mypoint_flutter_app/networking/api/product_api.dart' deferred as product_api;
import 'package:mypoint_flutter_app/shared/router_gage.dart';
import 'package:uuid/uuid.dart';
import '../../base/base_response_model.dart';
import '../../networking/restful_api_viewmodel.dart';
import '../../configs/constants.dart';
import '../../preference/contact_storage_service.dart';
import '../../preference/data_preference.dart';
import '../voucher/models/product_model.dart';
import '../webview/payment_web_view_screen.dart';
import 'model/payment_bank_account_info_model.dart';
import 'model/payment_method_model.dart';
import 'model/preview_order_payment_model.dart';

class TransactionDetailViewModel extends RestfulApiViewModel {
  final int definedCodeIndexBankAccount = 1000;
  var previewData = Rxn<PreviewOrderPaymentModel>();
  var paymentMethods = RxList<PaymentMethodModel>();
  var paymentBankAccounts = RxList<PaymentBankAccountInfoModel>();
  final RxBool isLoading = false.obs;
  final ProductModel product;
  String? metaData;
  final int quantity;
  final String? targetPhoneNumber;
  final RxBool usePoints = true.obs;
  var selectedPaymentMethodIndex = -1.obs;
  void Function(String message)? onShowAlertError;
  bool _productApiLoaded = false;

  Future<void> _ensureProductApiLoaded() async {
    if (_productApiLoaded) return;
    await product_api.loadLibrary();
    _productApiLoaded = true;
  }

  Future<BaseResponseModel<T>> _callProductApi<T>(Future<BaseResponseModel<T>> Function(dynamic api) fn) async {
    await _ensureProductApiLoaded();
    final api = product_api.ProductApi(client);
    return fn(api);
  }

  int get finalTotal {
    final totalPrice = previewData.value?.totalPrice ?? 0;
    final pointValue = previewData.value?.pointData?.point ?? 0;
    final finalTotal =
        usePoints.value && previewData.value?.pointData?.status == 1 ? totalPrice - pointValue : totalPrice;
    return finalTotal;
  }

  TransactionDetailViewModel({required this.product, required this.quantity, this.targetPhoneNumber, this.metaData});

  Future<void> refreshData() async {
    isLoading.value = true;
    await Future.wait([_getPreviewOrderPayment(), _getPaymentMethods(), _getPaymentBankAccounts()]);
    isLoading.value = false;
  }

  Future<void> requestPaymentProduct() async {
    showLoading();
    final requestId = Uuid().v4();
    int? point = usePoints.value ? previewData.value?.pointData?.point : 0;
    PaymentBankAccountInfoModel? selectedBankAccount;
    PaymentMethodModel? selectedPaymentMethod;
    bool? saveToken;
    if (finalTotal == 0) {
      point = previewData.value?.pointData?.point ?? 0;
    } else if (selectedPaymentMethodIndex >= definedCodeIndexBankAccount) {
      selectedBankAccount = paymentBankAccounts.value[selectedPaymentMethodIndex - definedCodeIndexBankAccount];
    } else if (selectedPaymentMethodIndex >= 0) {
      selectedPaymentMethod = paymentMethods.value[selectedPaymentMethodIndex];
      saveToken = selectedPaymentMethod.saveToken == true && selectedPaymentMethod.needSaveTokenWhenOrder == true;
    }
    try {
      final response = await _callProductApi(
        (api) => api.orderSubmitPayment(
          products: [product],
          quantity: quantity,
          requestId: requestId,
          point: point,
          cash: finalTotal,
          method: selectedPaymentMethod,
          paymentTokenId: selectedBankAccount?.id,
          saveToken: saveToken,
          metadata: metaData,
          targetPhoneNumber: targetPhoneNumber,
        ),
      );
      if (response.isSuccess) {
        final data = response.data;
        if ((data?.paymentUrl ?? "").isNotEmpty) {
          if ((targetPhoneNumber ?? "").isNotEmpty) {
            ContactStorageService().saveUsedContact(targetPhoneNumber ?? "");
          }
          Get.toNamed(
            paymentWebViewScreen,
            arguments: PaymentWebViewInput(
              url: data?.paymentUrl ?? "",
              isContract: false,
              orderId: data?.id ?? "",
              showAlertBack: true,
              callback: (result) {
                if (result == PaymentProcess.success) {
                  Get.offNamed(
                    transactionHistoryDetailScreen,
                    arguments: {"orderId": data?.id ?? "", "canBack": true},
                  );
                }
              },
            ),
          );
        } else if ((data?.redeemId ?? "").isNotEmpty && (data?.id ?? "").isNotEmpty) {
          Get.offNamed(transactionHistoryDetailScreen, arguments: {"orderId": data?.id ?? "", "canBack": true});
        } else {
          onShowAlertError?.call(response.errorMessage ?? Constants.commonError);
        }
      } else {
        onShowAlertError?.call(response.errorMessage ?? Constants.commonError);
      }
    } catch (error) {
      onShowAlertError?.call(Constants.commonError);
    } finally {
      hideLoading();
    }
  }

  Future<void> _getPreviewOrderPayment() async {
    String? token = DataPreference.instance.token ?? "";
    try {
      final body = {
        "product_id": product.id,
        "quantity": quantity,
        "price": product.amountToBePaid ?? 0,
        "access_token": token,
        "target_phone_number": targetPhoneNumber ?? "",
      };
      if (product.previewFlashSale?.isFlashSalePrice == true && product.previewFlashSale?.id != null) {
        body["flash_sale_id"] = product.previewFlashSale!.id;
      }
      if ((metaData ?? '').isNotEmpty) {
        body["metadata"] = metaData;
      }
      final response = await _callProductApi((api) => api.getPreviewOrderInfo(body));
      previewData.value = response.data;
    } catch (error) {
      debugPrint("Error fetching preview order payment: $error");
    }
  }

  Future<void> _getPaymentMethods() async {
    try {
      final response = await _callProductApi((api) => api.getPreviewPaymentMethods());
      paymentMethods.value = response.data ?? [];
    } catch (error) {
      debugPrint("Error fetching payment methods: $error");
    }
  }

  Future<void> _getPaymentBankAccounts() async {
    try {
      final response = await _callProductApi((api) => api.getPreviewOrderBankAccounts());
      paymentBankAccounts.value = response.data ?? [];
    } catch (error) {
      debugPrint("Error fetching payment bank accounts: $error");
    }
  }
}
