package com.sonic.lion.sub;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.api.services.androidpublisher.model.ProductPurchase;
import com.google.cloud.pubsub.v1.AckReplyConsumer;
import com.google.cloud.pubsub.v1.MessageReceiver;
import com.google.cloud.pubsub.v1.Subscriber;
import com.google.pubsub.v1.ProjectSubscriptionName;
import com.google.pubsub.v1.PubsubMessage;
import com.sonic.common.utils.LogUtils;
import com.sonic.lion.domain.entity.UserSubscriptionNotify;
import com.sonic.lion.domain.req.GoogleUploadReceiptReq;
import com.sonic.lion.service.GoogleService;
import com.sonic.lion.service.GoogleUploadReceiptService;
import com.sonic.lion.service.UserSubscriptionService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * https://developer.android.com/google/play/billing/rtdn-reference?hl=zh-cn
 */
@Component
@Slf4j
public class SubscribeAsyncGoogleSubPub implements ApplicationRunner, DisposableBean {

    @Value("${google.projectId}")
    private String projectId;
    @Value("${google.subscriptionId}")
    private String subscriptionId;

    @Autowired
    private UserSubscriptionService userSubscriptionService;

    @Autowired
    private GoogleService googleService;

    @Autowired
    private GoogleUploadReceiptService googleUploadReceiptService;

    private Subscriber subscriber = null;

    @Value("${spring.profiles.active}")
    private String env;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        if (!"product".equals(env)) {
            log.info("SubscribeAsyncGoogleSubPub not running env is not product !!!{}", env);
            return;
        }
        log.info("SubscribeAsyncGoogleSubPub was started!");

        Map<Integer, String> notificationMap = new HashMap<>();
        notificationMap.put(1, "SUBSCRIPTION_RECOVERED");
        notificationMap.put(2, "SUBSCRIPTION_RENEWED");
        notificationMap.put(3, "SUBSCRIPTION_CANCELED");
        notificationMap.put(4, "SUBSCRIPTION_PURCHASED");
        notificationMap.put(5, "SUBSCRIPTION_ON_HOLD");
        notificationMap.put(6, "SUBSCRIPTION_IN_GRACE_PERIOD");
        notificationMap.put(7, "SUBSCRIPTION_RESTARTED");
        notificationMap.put(8, "SUBSCRIPTION_PRICE_CHANGE_CONFIRMED");
        notificationMap.put(9, "SUBSCRIPTION_DEFERRED");
        notificationMap.put(10, "SUBSCRIPTION_PAUSED");
        notificationMap.put(11, "SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED");
        notificationMap.put(12, "SUBSCRIPTION_REVOKED");
        notificationMap.put(13, "SUBSCRIPTION_EXPIRED");

        try {
            start(notificationMap);
        } catch (Exception e) {
            log.error("SubscribeAsyncGoogleSubPub error!", e);
        }
    }

    public void start(Map<Integer, String> NotificationMap3) {
        subscribeAsync(projectId, subscriptionId, NotificationMap3);
    }


    /**
     * https://developer.android.com/google/play/billing/rtdn-reference
     *
     * @param projectId
     * @param subscriptionId
     * @param NotificationMap3
     */
    public void subscribeAsync(String projectId, String subscriptionId, Map<Integer, String> NotificationMap3) {
        ProjectSubscriptionName subscriptionName =
                ProjectSubscriptionName.of(projectId, subscriptionId);
        MessageReceiver receiver =
                (PubsubMessage message, AckReplyConsumer consumer) -> {
                    try {
                        LogUtils.setTraceId();
                        // Handle incoming message, then ack the received message.
                        String messageId = message.getMessageId();
                        String messageBody = message.getData().toStringUtf8();
                        log.info("===> subscribeAsync messageId:{} ,messageBody:{} ", messageId, messageBody);
                        JSONObject jsonObject = JSON.parseObject(messageBody);
                        JSONObject subscriptionNotification = jsonObject.getJSONObject("subscriptionNotification");
                        if (subscriptionNotification != null) {
                            Long notifyId = 0L;
                            Integer type = subscriptionNotification.getInteger("notificationType");
                            String typeDesc = NotificationMap3.get(type);
                            try {
                                notifyId = userSubscriptionService.addSubscriptionNotify("", messageId, messageBody, typeDesc, UserSubscriptionNotify.Platform.GOOGLE);
                            } catch (org.springframework.dao.DuplicateKeyException e) {
                                log.info("google 订阅消息已经被处理 messageId:{}", messageId);
                            }
                            try {
                                googleService.handSubscribeWebhook(notifyId, typeDesc, messageBody);
                            } catch (Exception e) {
                                log.info("google 处理失败 notifyId:{}", notifyId);
                                log.error("google 处理失败", e);
                                userSubscriptionService.failNotify(notifyId);
                            }
                        } else {
                            JSONObject oneTimeProductNotification = jsonObject.getJSONObject("oneTimeProductNotification");
                            if (oneTimeProductNotification != null) {
                                String token = oneTimeProductNotification.getString("purchaseToken");
                                String productId = oneTimeProductNotification.getString("sku");
                                boolean exitsRecepit = googleUploadReceiptService.countRecepit(token);
                                if (!exitsRecepit) {
                                    log.info("发现丢单 处理中...{} ,{}", productId, token);
                                    //处理丢单
                                    GoogleUploadReceiptReq googleUploadReceiptReq = new GoogleUploadReceiptReq();
                                    googleUploadReceiptReq.setProductId(productId);
                                    googleUploadReceiptReq.setReceipt(token);
                                    try {
                                        ProductPurchase productPurchase = googleService.googleCheck(productId, token);
                                        if(StringUtils.isNotBlank(productPurchase.getObfuscatedExternalProfileId())){
                                            log.info("开始处理google 丢单:{}",productPurchase.getObfuscatedExternalProfileId());
                                            googleUploadReceiptReq.setTradeNo(productPurchase.getObfuscatedExternalProfileId());
                                            googleService.uploadReceipt(googleUploadReceiptReq);
                                        }
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                        log.error("google 丢单补偿失败",e);
                                    }
                                }
                            }
                        }
                        consumer.ack();
                    } finally {
                        LogUtils.removeTraceId();
                    }
                };
        subscriber = Subscriber.newBuilder(subscriptionName, receiver).build();
        // Start the subscriber.
        subscriber.startAsync().awaitRunning();
    }

    @Override
    public void destroy() throws Exception {
        subscriber.stopAsync();
    }
}