package com.liquidnet.service.goblin.service.impl;

import com.fasterxml.jackson.databind.JsonNode;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.commons.lang.util.HttpUtil;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.PagedResult;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.goblin.dto.vo.*;
import com.liquidnet.service.goblin.service.IGoblinDigitalArtworkService;
import com.liquidnet.service.goblin.util.GoblinMongoUtils;
import com.liquidnet.service.goblin.util.GoblinRedisUtils;
import com.liquidnet.service.goblin.util.ObjectUtil;
import com.liquidnet.service.goblin.util.QueueUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;

import java.time.LocalDateTime;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class GoblinDigitalArtworkServiceImpl implements IGoblinDigitalArtworkService {
    @Autowired
    private QueueUtils queueUtils;
    @Autowired
    private GoblinRedisUtils goblinRedisUtils;
    @Autowired
    private GoblinMongoUtils goblinMongoUtils;


    @Autowired
    Environment env;
//    @Value("${liquidnet.service.galaxy.url}")// TODO: 2022/3/31 ==zhanggb
//    private String sevGalaxyUrl;

    @Override
    public GoblinDigitalArtworkPageVo page(String uid, Integer pageNum, Integer pageSize) {
        GoblinDigitalArtworkPageVo pageVo = GoblinDigitalArtworkPageVo.getNew();
        long artworkNum = goblinRedisUtils.countUserDigitalArtwork(uid);
        if (artworkNum > 0) {
            if (artworkNum > 30 && pageNum * pageSize > 30) {// 查询Mongo
                PagedResult<GoblinDigitalArtworkListVo> listVoPagedResult = goblinMongoUtils.getUserDigitalArtworkListVos(uid, pageNum, pageSize);
                listVoPagedResult.setTotal(artworkNum, pageSize);
                pageVo.setArtworkNum((int) artworkNum).setPagedResult(listVoPagedResult);
            } else {
                PagedResult<GoblinDigitalArtworkListVo> listVoPagedResult = ObjectUtil.getGoblinDigitalArtworkListVoPagedResult();
                List<GoblinDigitalArtworkListVo> list = ObjectUtil.getGoblinDigitalArtworkListVoArrayList();
                List<String> userDigitalArtworkIds = goblinRedisUtils.getUserDigitalArtworkIds(uid);
                if (!CollectionUtils.isEmpty(userDigitalArtworkIds)) {
                    int cacheSize = userDigitalArtworkIds.size(), cacheNum = cacheSize / pageSize + 1;// 分几页
                    int fromIndex = Math.min(Math.min(cacheNum, pageNum - 1) * pageSize, cacheSize - 1);
                    List<String> subList = userDigitalArtworkIds.subList(fromIndex, Math.min(fromIndex + pageSize, cacheSize));

                    LocalDateTime now = LocalDateTime.now(), toCheckTime = now.minusSeconds(15);
                    int subSize = subList.size();
                    for (int i = 0; i < subSize; i++) {
                        String artworkId = subList.get(i);
                        GoblinDigitalArtworkVo userDigitalArtworkVo = goblinRedisUtils.getUserDigitalArtworkVo(artworkId);
                        if (null != userDigitalArtworkVo) {
                            GoblinGoodsSkuInfoVo goodsSkuInfoVo = goblinRedisUtils.getGoodsSkuInfoVo(userDigitalArtworkVo.getSkuId());

                            GoblinDigitalArtworkListVo listVo = GoblinDigitalArtworkListVo.getNew().copy(userDigitalArtworkVo);
                            listVo.setName(goodsSkuInfoVo.getName());
                            listVo.setSubtitle(goodsSkuInfoVo.getSubtitle());
                            listVo.setCoverPic(goodsSkuInfoVo.getSkuPic());
                            listVo.setEdition(goodsSkuInfoVo.getSkuStock());
                            listVo.setUnbox(goodsSkuInfoVo.getUnbox());
                            listVo.setOpeningTime(goodsSkuInfoVo.getOpeningTime());

                            if (listVo.getCreatedAt().isBefore(toCheckTime)) {// 15秒前创建的藏品，去主动核实发行交易状态
                                List<String> checkRespDataList = this.checkNftTradeFromGalaxy(uid, userDigitalArtworkVo.getOrderId(), goodsSkuInfoVo.getRouteType());
                                this.updateUserDigitalArtworkByChainTrade(userDigitalArtworkVo, listVo, checkRespDataList, now);
                            }

                            list.add(listVo);
                        }
                    }

                    listVoPagedResult.setList(list).setTotal(artworkNum, pageSize);
                    pageVo.setArtworkNum((int) artworkNum).setPagedResult(listVoPagedResult);
                }
            }
        }
        return pageVo;
    }

    @Override
    public GoblinDigitalArtworkInfoVo info(String uid, String artworkId) {
        GoblinDigitalArtworkVo userDigitalArtworkVo = goblinRedisUtils.getUserDigitalArtworkVo(artworkId);
        if (null != userDigitalArtworkVo && userDigitalArtworkVo.getUid().equals(uid)) {
            GoblinDigitalArtworkInfoVo artworkInfoVo = GoblinDigitalArtworkInfoVo.getNew().copy(userDigitalArtworkVo);

            GoblinGoodsSkuInfoVo goodsSkuInfoVo = goblinRedisUtils.getGoodsSkuInfoVo(userDigitalArtworkVo.getSkuId());
            GoblinGoodsInfoVo goodsInfoVo = goblinRedisUtils.getGoodsInfoVo(goodsSkuInfoVo.getSpuId());

            artworkInfoVo.setName(goodsSkuInfoVo.getName());
            artworkInfoVo.setSubtitle(goodsSkuInfoVo.getSubtitle());
            artworkInfoVo.setMaterialType(goodsSkuInfoVo.getMaterialType());
            artworkInfoVo.setMaterialUrl(goodsSkuInfoVo.getMaterialUrl());
            artworkInfoVo.setEdition(goodsSkuInfoVo.getSkuStock());
            artworkInfoVo.setAuthor(goodsInfoVo.getAuthor());
            artworkInfoVo.setPublisher(goodsInfoVo.getPublisher());
            artworkInfoVo.setDetails(goodsSkuInfoVo.getDetails());

            return artworkInfoVo;
        }
        return null;
    }

    /* -------------------------------------------------------------------------------------------------------------- */

    private void updateUserDigitalArtworkByChainTrade(GoblinDigitalArtworkVo userDigitalArtworkVo, GoblinDigitalArtworkListVo listVo,
                                                      List<String> checkRespDataList, LocalDateTime now) {
        if (!CollectionUtils.isEmpty(checkRespDataList)) {
            String nftId = checkRespDataList.get(0);
            String nftPublishChainTimestamp = checkRespDataList.get(1);
            String nftPublishTxHash = checkRespDataList.get(2);
            String nftBuyChainTimestamp = checkRespDataList.get(3);
            String nftBuyTxHash = checkRespDataList.get(4);

            listVo.setState(1);
            listVo.setEditionSn(Integer.valueOf(nftId.substring(nftId.indexOf("_") + 1)));

            userDigitalArtworkVo.setEditionSn(listVo.getEditionSn());
            userDigitalArtworkVo.setNftId(nftId);
            userDigitalArtworkVo.setReleaseAt(nftPublishChainTimestamp);
            userDigitalArtworkVo.setReleaseTxhash(nftPublishTxHash);
            userDigitalArtworkVo.setTradingAt(nftBuyChainTimestamp);
            userDigitalArtworkVo.setTradingTxhash(nftBuyTxHash);
            userDigitalArtworkVo.setState(1);
            userDigitalArtworkVo.setUpdatedAt(now);

            goblinRedisUtils.setUserDigitalArtworkVo(userDigitalArtworkVo.getArtworkId(), userDigitalArtworkVo);
            goblinMongoUtils.updateUserDigitalArtworkVoByChainTrade(userDigitalArtworkVo);

            queueUtils.sendMsgByRedis(MQConst.GoblinQueue.SQL_ARTWORK_GEN.getKey(),
                    SqlMapping.get("goblin_user_digital_artwork.update_for_chain",
                            userDigitalArtworkVo.getEditionSn(), userDigitalArtworkVo.getNftId(), userDigitalArtworkVo.getReleaseTxhash(),
                            userDigitalArtworkVo.getReleaseAt(), userDigitalArtworkVo.getTradingTxhash(), userDigitalArtworkVo.getTradingAt(),
                            userDigitalArtworkVo.getState(), userDigitalArtworkVo.getUpdatedAt())
            );
        }
    }

    private List<String> checkNftTradeFromGalaxy(String uid, String orderId, String routerType) {
        LinkedMultiValueMap<String, String> paramsMap = CollectionUtil.linkedMultiValueMapStringString();
        paramsMap.add("userId", uid);
        paramsMap.add("nftOrderPayId", orderId);// TODO: 2022/3/31 ==zhanggb
        paramsMap.add("routerType", routerType);

//        String postUrl = sevGalaxyUrl + "/user/register", blockChainAddress;// TODO: 2022/3/31 ==zhanggb
        String postUrl = "https://ENVgalaxy.zhengzai.tv/galaxy/nftTrade/nftPublishAndBuyResultQuery".replace("ENV", env.getProperty(CurrentUtil.CK_ENV_ACTIVE)), blockChainAddress;
        try {
            LinkedMultiValueMap<String, String> headerMap = CollectionUtil.linkedMultiValueMapStringString();
            headerMap.add("Accept", MediaType.APPLICATION_JSON_VALUE);
            String postRespStr = HttpUtil.post(postUrl, paramsMap, headerMap);
            JsonNode postRespJNode = JsonUtils.fromJson(postRespStr, JsonNode.class);
            if (null == postRespJNode || !postRespJNode.get("code").asText().equals("0")) {
                log.warn("#NFT发行购买结果查询:查询失败[paramsMap={},postRespStr={}]", paramsMap, postRespStr);
                return null;
            }
            JsonNode postRespDataJNode = postRespJNode.get("data");

            List<String> respDataList = CollectionUtil.arrayListString();
            respDataList.add(postRespDataJNode.get("nftId").asText());
            respDataList.add(postRespDataJNode.get("nftPublishChainTimestamp").asText());
            respDataList.add(postRespDataJNode.get("nftPublishTxHash").asText());
            respDataList.add(postRespDataJNode.get("nftBuyChainTimestamp").asText());
            respDataList.add(postRespDataJNode.get("nftBuyTxHash").asText());
            return respDataList;
        } catch (Exception e) {
            log.error("Ex.NFT发行购买结果查询:请求异常[UID={},url={},paramsMap={}],ex:{}", uid, postUrl, paramsMap, e.getMessage());
            return null;
        }
    }
}
