package com.atmob.voiceai.data.repositories;


import android.os.Handler;

import androidx.lifecycle.MutableLiveData;

import com.android.billingclient.api.BillingClient;
import com.android.billingclient.api.Purchase;
import com.atmob.app.lib.handler.RxHttpHandler;
import com.atmob.common.logging.AtmobLog;
import com.atmob.voiceai.data.api.AtmobApi;
import com.atmob.voiceai.data.api.bean.MemberInfoBean;
import com.atmob.voiceai.data.api.request.BaseRequest;
import com.atmob.voiceai.data.api.request.OrderPayRequest;
import com.atmob.voiceai.data.api.request.OrderStatusRequest;
import com.atmob.voiceai.data.api.request.PayGoodsRequest;
import com.atmob.voiceai.data.api.request.SubResumeRequest;
import com.atmob.voiceai.data.api.response.OrderPayResponse;
import com.atmob.voiceai.data.api.response.OrderStatusResponse;
import com.atmob.voiceai.data.api.response.PayGoodsResponse;
import com.atmob.voiceai.data.api.response.UserInfoResponse;
import com.atmob.voiceai.data.consts.ErrorCode;
import com.atmob.voiceai.data.consts.EventId;
import com.atmob.voiceai.handlers.EventHandler;
import com.atmob.voiceai.sdk.billing.GPBillingClient;
import com.atmob.voiceai.utils.BoxingUtil;

import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.inject.Inject;
import javax.inject.Singleton;

import atmob.reactivex.rxjava3.annotations.NonNull;
import atmob.reactivex.rxjava3.core.Observable;
import atmob.reactivex.rxjava3.core.Single;
import atmob.reactivex.rxjava3.core.SingleObserver;
import atmob.reactivex.rxjava3.core.SingleSource;
import atmob.reactivex.rxjava3.disposables.Disposable;
import atmob.reactivex.rxjava3.functions.Function;
import atmob.rxjava.utils.RxJavaUtil;

@Singleton
public class MemberRepository {


    private final MutableLiveData<Boolean> isMember = new MutableLiveData<>();
    private final AtmobApi atmobApi;
    private final GPBillingClient gpBillingClient;
    private boolean requestUserInfoDisabled;
    private final Handler refreshMemberHandler = new Handler();

    @Inject
    public MemberRepository(AtmobApi atmobApi, GPBillingClient gpBillingClient) {
        this.atmobApi = atmobApi;
        this.gpBillingClient = gpBillingClient;
        refreshUserData();
    }


    public MutableLiveData<Boolean> getIsMember() {
        return isMember;
    }

    public Single<Object> subscriptionResume() {
        return gpBillingClient.queryPurchase(BillingClient.ProductType.SUBS)
                .map(list -> {
                    if (list == null || list.isEmpty()) {
                        EventHandler.report(EventId.restorenosub_001);
                        throw new RxHttpHandler.ServerErrorException(ErrorCode.ERROR_SUBSCRIPTION_NOT_FOUND, "Unsuccessful: Subscription not found");
                    }
                    return list;
                })
                .filter(purchases -> purchases != null && !purchases.isEmpty())
                .toSingle()
                .flatMap(purchases -> Observable.fromIterable(purchases)
                        .filter(purchase -> purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED)
                        .firstOrError()
                        .flatMap(purchase -> {
                            String googlePurchaseToken = purchase.getPurchaseToken();
                            return subscriptionResume(4, 1, googlePurchaseToken);
                        }))
                .compose(RxJavaUtil.SingleSchedule.io2Main())
                .doOnSuccess(o -> refreshUserData());
    }


    private Single<Object> subscriptionResume(int payMethod, int payPlatform, String receiptData) {
        return atmobApi.subscriptionResume(new SubResumeRequest(payMethod, payPlatform, receiptData))
                .compose(RxHttpHandler.handle(true))
                .compose(RxJavaUtil.SingleSchedule.io2Main());
    }

    public Single<PayGoodsResponse> payGoodsList() {
        return atmobApi.payGoodsList(new PayGoodsRequest(false))
                .compose(RxHttpHandler.handle(true))
                .compose(RxJavaUtil.SingleSchedule.io2Main());
    }

    public Single<OrderPayResponse> requestGoodsPayOrder(int itemId, int payPlatform, int payMethod) {
        return gpBillingClient.queryPurchase(BillingClient.ProductType.SUBS)
                .map(list -> {
                    if (list != null && !list.isEmpty()) {
                        throw new RxHttpHandler.ServerErrorException(-1, "Unsuccessful: Subscription already exists, please click restore");
                    }
                    return list;
                })
                .flatMap(purchases -> requestPayOrder(itemId, payPlatform, payMethod))
                .compose(RxJavaUtil.SingleSchedule.io2Main());

    }

    private Single<OrderPayResponse> requestPayOrder(int itemId, int payPlatform, int payMethod) {
        return atmobApi.orderPay(new OrderPayRequest(itemId, payPlatform, payMethod))
                .compose(RxHttpHandler.handle(false))
                .compose(RxJavaUtil.SingleSchedule.io2Main());
    }

    /**
     * 0-查询失败，继续轮询
     * 1-未支付，继续轮询
     * 2-支付成功
     * 3-支付关闭
     * 4-已退款
     *
     * @param outTradeNo
     * @param receiptData
     * @return
     */
    public Single<Boolean> orderStatus(String outTradeNo, String receiptData) {
        return atmobApi.orderStatus(new OrderStatusRequest(outTradeNo, receiptData))
                .compose(RxHttpHandler.handle(false))
                .map(OrderStatusResponse::getPayStatus)
                .map(integer -> {
                    AtmobLog.d("orderStatus", "status ==> " + integer);
                    if (BoxingUtil.boxing(integer) == 0 || BoxingUtil.boxing(integer) == 1) {
                        throw new Exception("支付未完成, status ==> " + integer);
                    }
                    return integer;
                })
                .retryWhen(RxJavaUtil.retryWhen(null, 100, 3, TimeUnit.SECONDS))
                .onErrorReturnItem(0)
                .map(integer -> integer == 2)
                .compose(RxJavaUtil.SingleSchedule.io2Main())
                .doOnTerminate(this::refreshUserData);
    }


    public void refreshUserData() {
        if (requestUserInfoDisabled) {
            return;
        }
        userInfo().subscribe(new SingleObserver<UserInfoResponse>() {


            @Override
            public void onSubscribe(@NonNull Disposable d) {
                requestUserInfoDisabled = true;
            }

            @Override
            public void onSuccess(@NonNull UserInfoResponse userInfoResponse) {
                requestUserInfoDisabled = false;
            }

            @Override
            public void onError(@NonNull Throwable e) {
                requestUserInfoDisabled = false;
            }
        });
    }


    private Single<UserInfoResponse> userInfo() {
        return atmobApi.userInfo(new BaseRequest())
                .compose(RxHttpHandler.handle(true))
                .retryWhen(RxJavaUtil.exponentialBackOff(null, 3, TimeUnit.SECONDS))
                .compose(RxJavaUtil.SingleSchedule.io2Main())
                .doOnSuccess(userInfoResponse -> {
                    MemberInfoBean memberInfo = userInfoResponse.getMemberInfo();
                    if (memberInfo != null) {
                        isMember.setValue(memberInfo.isIsMember());
                        refreshMemberHandler.removeCallbacksAndMessages(null);
                        if (memberInfo.isIsMember()) {
                            refreshMemberHandler.postDelayed(this::refreshUserData, memberInfo.getExpireTime() - memberInfo.getTimestamp());
                        } else {
                            VoiceAIRepository.getVoiceAIRepository().refreshVoiceInfo();
                        }
                    }
                });
    }

}
