package com.datarecovery.master.data.repositories;


import android.util.Pair;

import com.atmob.common.runtime.ActivityUtil;
import com.datarecovery.master.R;
import com.datarecovery.master.data.api.AtmobApi;
import com.datarecovery.master.data.api.bean.PayOptions;
import com.datarecovery.master.data.api.bean.WechatPaymentSignBean;
import com.datarecovery.master.data.api.request.MemberDetailRequest;
import com.datarecovery.master.data.api.request.MemberPayRequest;
import com.datarecovery.master.data.api.request.PaymentStatusRequest;
import com.datarecovery.master.data.api.response.MemberDetailResponse;
import com.datarecovery.master.data.api.response.MemberPayResponse;
import com.datarecovery.master.data.api.response.PaymentStatusResponse;
import com.datarecovery.master.data.consts.Constants;
import com.datarecovery.master.data.consts.ErrorCode;
import com.datarecovery.master.data.consts.EventId;
import com.datarecovery.master.handler.EventHelper;
import com.datarecovery.master.module.login.LoginActivity;
import com.datarecovery.master.module.member.MemberType;
import com.datarecovery.master.utils.BoxingUtil;
import com.datarecovery.master.utils.Maps;
import com.datarecovery.master.utils.OrderReportHelper;
import com.datarecovery.master.utils.ReportUtil;
import com.datarecovery.master.utils.RxHttpHandler;
import com.datarecovery.master.utils.ToastUtil;
import com.google.gson.Gson;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

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

import atmob.reactivex.rxjava3.annotations.NonNull;
import atmob.reactivex.rxjava3.core.Single;
import atmob.reactivex.rxjava3.core.SingleObserver;
import atmob.reactivex.rxjava3.disposables.Disposable;
import atmob.rxjava.utils.RxJavaUtil;
import plus.pay.AgilePay;
import plus.pay.alipay.AlipayInfo;
import plus.pay.listener.AgilePayState;
import plus.pay.wxpay.WXpayInfo;

@Singleton
public class MemberRepository {


    private final AtmobApi atmobApi;
    private final DeviceFuncRepository deviceFuncRepository;
    private final Gson gson;
    private final PayRepository payRepository;

    @Inject
    public MemberRepository(AtmobApi atmobApi, DeviceFuncRepository deviceFuncRepository, PayRepository payRepository, Gson gson) {
        this.atmobApi = atmobApi;
        this.deviceFuncRepository = deviceFuncRepository;
        this.payRepository = payRepository;
        this.gson = gson;
    }

    public void payOrder(@NonNull PayOptions payOptions) {
        if (payOptions == null) {
            throw new NullPointerException("payOptions is null");
        }
        requestPayOrder(payOptions.getGoodsId(), payOptions.getPayPlatform(), payOptions.getPayMethod()).subscribe(new SingleObserver<MemberPayResponse>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                payOptions.addDisposable(d);
                payOptions.setShowLoadingEvent(true);
            }

            @Override
            public void onSuccess(@NonNull MemberPayResponse memberPayResponse) {
                payOptions.setShowLoadingEvent(false);
                if (payOptions.getPayPlatform() == 1 && payOptions.getPayMethod() == 2) {
                    onWeChatPay(memberPayResponse.getWechatPayPrepayJson(), memberPayResponse.getOutTradeNo(), payOptions);
                } else if (payOptions.getPayPlatform() == 4 && payOptions.getPayMethod() == 2) {
                    onWeChatScanPay(memberPayResponse.getWechatPayPrepayJson(), memberPayResponse.getOutTradeNo(), payOptions);
                } else if (payOptions.getPayPlatform() == 1 && payOptions.getPayMethod() == 1) {
                    onAliPay(memberPayResponse.getAlipayOrderString(), memberPayResponse.getOutTradeNo(), payOptions);
                } else if (payOptions.getPayPlatform() == 4 && payOptions.getPayMethod() == 1) {
                    onAliPayScan(memberPayResponse.getAlipayQrcodeHtml(), memberPayResponse.getOutTradeNo(), payOptions);
                }
            }

            @Override
            public void onError(@NonNull Throwable throwable) {
                throwable.printStackTrace();
                payOptions.setShowLoadingEvent(false);
                if (throwable instanceof RxHttpHandler.ServerErrorException) {
                    RxHttpHandler.ServerErrorException serverErrorException = (RxHttpHandler.ServerErrorException) throwable;
                    if (serverErrorException.getCode() == ErrorCode.ERROR_CODE_NO_LOGIN_ERROR) {
                        ToastUtil.show(R.string.no_login, ToastUtil.LENGTH_SHORT);
                        LoginActivity.start(ActivityUtil.getTopActivity(), ReportUtil.getReportId(payOptions.getMemberType()));
                    } else if (serverErrorException.getCode() == ErrorCode.ERROR_CODE_HAS_PERMISSION_ERROR) {
                        ToastUtil.show(R.string.member_has_this_permission, ToastUtil.LENGTH_SHORT);
                        deviceFuncRepository.refreshFuncAuths();
                        payRepository.refreshOrderPageList();
                    } else {
                        ToastUtil.show(serverErrorException.getMsg(), ToastUtil.LENGTH_SHORT);
                    }
                } else {
                    ToastUtil.show(R.string.member_payment_failed, ToastUtil.LENGTH_SHORT);
                }
            }
        });
    }

    private void onAliPayScan(String s, String orderId, @NonNull PayOptions payOptions) {
        payOptions.setShowAlQRPaymentEvent(new Pair<>(s, orderId));
    }

    private void onAliPay(String s, String orderId, @NonNull PayOptions payOptions) {
        AlipayInfo alipayInfo = new AlipayInfo();
        alipayInfo.setContent(s);
        requestSdkPay(alipayInfo, orderId, payOptions, Constants.PAYMENT_WAY_ALIPAY);
    }

    private void onWeChatScanPay(String s, String orderId, @NonNull PayOptions payOptions) {
        payOptions.setShowWxQRPaymentEvent(new Pair<>(s, orderId));
    }


    private void onWeChatPay(String s, String orderId, @NonNull PayOptions payOptions) {
        try {
            WechatPaymentSignBean wechatPaymentSignBean = gson.fromJson(s, WechatPaymentSignBean.class);
            WXpayInfo wXpayInfo = new WXpayInfo();
            wXpayInfo.setAppid(wechatPaymentSignBean.getAppId());
            wXpayInfo.setPartnerid(wechatPaymentSignBean.getPartnerId());
            wXpayInfo.setPrepayid(wechatPaymentSignBean.getPrePayId());
            wXpayInfo.set_package(wechatPaymentSignBean.getPackageName());
            wXpayInfo.setNoncestr(wechatPaymentSignBean.getRandomStr());
            wXpayInfo.setTimestamp(wechatPaymentSignBean.getTimeStamp());
            wXpayInfo.setSign(wechatPaymentSignBean.getSign());
            requestSdkPay(wXpayInfo, orderId, payOptions, Constants.PAYMENT_WAY_WECHAT);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void requestSdkPay(Object payInfo, String orderId, @NonNull PayOptions payOptions, int payWay) {
        AgilePay.pay(payInfo, ActivityUtil.getTopActivity(), new AgilePayState() {
            @Override
            public void error(int errno, String error) {
                if (errno == 6001) {
                    //用户取消支付
                    EventHelper.report(EventId.hf1000606, Maps.asMap(EventId.EVENT_ID, "hf11028"));
                    return;
                }
                EventHelper.report(EventId.hf1000606, Maps.asMap(EventId.EVENT_ID, "hf11022"));
                ToastUtil.show(R.string.member_payment_failed, ToastUtil.LENGTH_SHORT);
            }

            @Override
            public void payError(int errno, String error) {
                if (errno == 6001) {
                    //用户取消支付
                    EventHelper.report(EventId.hf1000606, Maps.asMap(EventId.EVENT_ID, "hf11028"));
                    return;
                }
                EventHelper.report(EventId.hf1000606, Maps.asMap(EventId.EVENT_ID, "hf11022"));
                ToastUtil.show(R.string.member_payment_failed, ToastUtil.LENGTH_SHORT);
            }

            @Override
            public void paySuccess(String result) {
                EventHelper.reportPay(payOptions.getAmount(), orderId, payWay, payOptions.getGoodsName());
                payOptions.addDisposable(queryOrderStatus(orderId, payWay, payOptions, true, false));
            }

            @Override
            public void payBefore() {

            }
        });
    }

    public @NonNull Disposable queryOrderStatus(String orderId, int payWay, @NonNull PayOptions payOptions, boolean showLoading, boolean isReportPay) {
        if (isReportPay) {
            OrderReportHelper.recordOrderId(payOptions.getAmount(), orderId, payWay, payOptions.getGoodsName());
        }
        return getPayStatus(orderId, 100, 3)
                .doOnSubscribe(disposable -> {
                    if (showLoading) {
                        payOptions.setShowLoadingEvent(true);
                        payOptions.addDisposable(RxJavaUtil.timer(10, TimeUnit.SECONDS, () -> payOptions.setShowLoadingEvent(false)));
                    }
                })
                .doOnSuccess(success -> {
                    if (isReportPay) {
                        if (BoxingUtil.boxing(success)) {
                            EventHelper.reportPay(payOptions.getAmount(), orderId, payWay, payOptions.getGoodsName());
                        }
                    }
                })
                .subscribe(aBoolean -> {
                    payOptions.setShowLoadingEvent(false);
                    if (BoxingUtil.boxing(aBoolean)) {
                        EventHelper.report(EventId.hf1000604, Maps.asMap(EventId.EVENT_ID, ReportUtil.getReportId(payOptions.getMemberType())));
                        Map<String, Object> map = new HashMap<>();
                        if (Objects.equals(payOptions.getMemberType(), MemberType.APP_SUPER_RECOVER)) {
                            map.put(EventId.EVENT_ID, "hf11026");
                            EventHelper.report(EventId.hf1000605, map);
                        } else if (Objects.equals(payOptions.getMemberType(), MemberType.APP_IMAGE_CLEAN) && payOptions.isPermanent()) {
                            map.put(EventId.EVENT_ID, "hf11027");
                            EventHelper.report(EventId.hf1000605, map);
                        } else {
                            map.put(EventId.EVENT_ID, "hf11025");
                        }
                        map.put(EventId.EVENT_TYPE1, ReportUtil.getReportId(payOptions.getMemberType()));
                        EventHelper.report(EventId.hf1000605, map);
                        payRepository.refreshOrderPageList();
                        payOptions.setOnSubscribeSuccessEvent(orderId);
                    }
                }, throwable -> {
                    throwable.printStackTrace();
                    payOptions.setShowLoadingEvent(false);
                });
    }


    public Single<MemberDetailResponse> memberDetail(@MemberType String type) {
        return atmobApi.memberDetail(new MemberDetailRequest(type))
                .compose(RxHttpHandler.handle(false))
                .compose(RxJavaUtil.SingleSchedule.io2Main());
    }

    public Single<MemberPayResponse> requestPayOrder(int itemId, int payPlatform, int payMethod) {
        return atmobApi.requestPayOrder(new MemberPayRequest(itemId, payPlatform, payMethod))
                .compose(RxHttpHandler.handle(false))
                .compose(RxJavaUtil.SingleSchedule.io2Main());
    }


    /**
     * 0-查询失败，继续轮询
     * 1-未支付，继续轮询
     * 2-支付成功
     * 3-支付关闭
     * 4-已退款
     */
    public Single<Boolean> getPayStatus(String orderId, int maxReyTimes, long retryInterval) {
        return atmobApi.getPayStatus(new PaymentStatusRequest(orderId))
                .compose(RxHttpHandler.handle(false))
                .map(PaymentStatusResponse::getStatus)
                .doOnSuccess(status -> {
                    if (status != 0 && status != 1) {
                        OrderReportHelper.removeOderId(orderId);
                    }
                })
                .map(integer -> {
                    if (BoxingUtil.boxing(integer) == 0 || BoxingUtil.boxing(integer) == 1) {
                        throw new Exception("支付未完成, status ==> " + integer);
                    }
                    return integer;
                })
                .retryWhen(RxJavaUtil.retryWhen(null, maxReyTimes, retryInterval, TimeUnit.SECONDS))
                .onErrorReturnItem(0)
                .map(integer -> integer == 2)
                .compose(RxJavaUtil.SingleSchedule.io2Main())
                .doOnTerminate(deviceFuncRepository::refreshFuncAuths);
    }


}
