package com.liquidnet.service.galaxy.utils;

import com.liquidnet.common.cache.redis.util.RedisUtil;
import com.liquidnet.commons.lang.util.*;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.galaxy.constant.GalaxyConstant;
import com.liquidnet.service.galaxy.constant.GalaxyEnum;
import com.liquidnet.service.galaxy.dto.bo.*;
import com.liquidnet.service.galaxy.dto.vo.mongo.*;
import com.mongodb.client.result.UpdateResult;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Component
public class DataUtils {
    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private QueueUtil queueUtil;

    private long keyExpireTime = 3600*24*30;

    public void setGalaxyUserInfo(String routerType,String userId, GalaxyUserInfoBo userInfoBo) {
        String userType = GalaxyEnum.RegisterTypeEnum.COMPANY.getCode();
        redisUtil.set(GalaxyConstant.REDIS_KEY_GALAXY_USER.concat(routerType).concat(":") + userId,userInfoBo,keyExpireTime);
        //入库mongo
        GalaxyUserInfoVo userInfoVo = GalaxyUserInfoVo.getNew();
        BeanUtil.copy(userInfoBo,userInfoVo);

        userInfoVo.setCreatedAt(LocalDateTime.now());
        mongoTemplate.save(userInfoVo,GalaxyUserInfoVo.class.getSimpleName());
//        insert into galaxy_user_info (mid, user_id, user_name, user_type, mobile, id_card_type
//                , id_card, mnemonic, index,user_identification, user_pub_key
//                , user_pri_key, block_chain_address, router_type,created_at, updated_at)
        try{
            queueUtil.sendMySqlRedis(
                    SqlMapping.get("galaxy_user_info.insert"),
                    new Object[]{userId,userInfoBo.getUserName(),userType,userInfoBo.getMobile(),userInfoBo.getIdCardType()
                                 ,userInfoBo.getIdCard(),userInfoBo.getMnemonic(),userInfoBo.getIndex(),userInfoBo.getUserIdentification(),userInfoBo.getUserPubKey()
                                 ,userInfoBo.getUserPriKey(),userInfoBo.getBlockChainAddress(),userInfoBo.getRouterType(),new Date(),null
                    }
                    , MQConst.GalaxyQueue.SQL_USER_INFO.getKey()
            );
        }catch(Exception e){
            log.error(e.getMessage(),e);
            log.error("#setGalaxyUserInfo error ==> MESSAGE:{}",e.getMessage());
        }
    }

    public GalaxyUserInfoBo getGalaxyUserInfo(String routerType,String userId) {
        Object obj = redisUtil.get(GalaxyConstant.REDIS_KEY_GALAXY_USER.concat(routerType).concat(":") + userId);
        if(obj!=null){
            return (GalaxyUserInfoBo) obj;
        }else {
            GalaxyUserInfoVo userInfoVo = mongoTemplate.findOne(Query.query(Criteria.where("userId").is(userId)), GalaxyUserInfoVo.class, GalaxyUserInfoVo.class.getSimpleName());
            if (userInfoVo == null) {
                return null;
            }
            GalaxyUserInfoBo userInfoBo = GalaxyUserInfoBo.getNew();
            BeanUtil.copy(userInfoVo,userInfoBo);

            redisUtil.set(GalaxyConstant.REDIS_KEY_GALAXY_USER.concat(routerType).concat(":") + userId, userInfoBo);
            return userInfoBo;
        }
    }

    public void setSeriesNftUploadBo(String routerType,String skuId, GalaxySeriesNftUploadBo seriesNftUploadBo) {
        redisUtil.set(GalaxyConstant.REDIS_KEY_GALAXY_SERIES_NFT_UPLOAD.concat(routerType).concat(":") + skuId,seriesNftUploadBo,keyExpireTime);

        //mongo入库
        GalaxySeriesNftUploadVo seriesNftUploadVo = GalaxySeriesNftUploadVo.getNew();
        BeanUtil.copy(seriesNftUploadBo,seriesNftUploadVo);
        seriesNftUploadVo.setCreatedAt(LocalDateTime.now());
        mongoTemplate.save(seriesNftUploadVo,GalaxySeriesNftUploadVo.class.getSimpleName());
    }

    public GalaxySeriesNftUploadBo getSeriesNftUploadBo(String routerType,String skuId) {
        Object obj = redisUtil.get(GalaxyConstant.REDIS_KEY_GALAXY_SERIES_NFT_UPLOAD.concat(routerType).concat(":") + skuId);
        if(obj!=null){
            return (GalaxySeriesNftUploadBo) obj;
        }else {
            //设置查询参数
            Criteria criteria = Criteria.where("routerType").is(routerType);
            String userId = CurrentUtil.getCurrentUid();
            if(StringUtil.isNotEmpty(skuId)){
                criteria = criteria.and("skuId").is(skuId);
            }

            GalaxySeriesNftUploadVo seriesNftUploadVo = mongoTemplate.findOne(Query.query(criteria), GalaxySeriesNftUploadVo.class, GalaxySeriesNftUploadVo.class.getSimpleName());
            if (seriesNftUploadVo == null) {
                return null;
            }
            GalaxySeriesNftUploadBo seriesNftUploadBo = GalaxySeriesNftUploadBo.getNew();
            BeanUtil.copy(seriesNftUploadVo,seriesNftUploadBo);

            redisUtil.set(GalaxyConstant.REDIS_KEY_GALAXY_SERIES_NFT_UPLOAD.concat(routerType).concat(":") + skuId, seriesNftUploadBo);
            return seriesNftUploadBo;
        }
    }

    public void setSeriesInfoBo(String routerType,String seriesCode, GalaxySeriesInfoBo seriesInfoBo) {
        redisUtil.set(GalaxyConstant.REDIS_KEY_GALAXY_SERIES.concat(routerType).concat(":") + seriesCode,seriesInfoBo,keyExpireTime);

//        insert into galaxy_series_info (mid, series_info_id, series_name, series_code, series_id, total_count
//                , crt_count,series_claim_task_id, series_claim_status, cover_url, series_desc
//                , nft_count,router_type, created_at, updated_at)
        Integer nftCount = 1;//默认为一个系列包含一个NFT

        //mongo入库
        GalaxySeriesInfoVo seriesInfoVo = GalaxySeriesInfoVo.getNew();
        BeanUtil.copy(seriesInfoBo,seriesInfoVo);
        seriesInfoVo.setCreatedAt(DateUtil.format(LocalDateTime.now(), DateUtil.Formatter.yyyyMMddHHmmss));
        mongoTemplate.save(seriesInfoVo,GalaxySeriesInfoVo.class.getSimpleName());

        try{
            queueUtil.sendMySqlRedis(
                    SqlMapping.get("galaxy_series_info.insert"),
                    new Object[]{seriesInfoBo.getSeriesInfoId(),seriesInfoBo.getSeriesName(),seriesCode,null,seriesInfoBo.getTotalCount()
                            ,seriesInfoBo.getCrtCount(),seriesInfoBo.getSeriesClaimTaskId(),seriesInfoBo.getSeriesClaimStatus(),seriesInfoBo.getCoverUrl(),seriesInfoBo.getSeriesDesc()
                            ,nftCount,seriesInfoBo.getRouterType(),LocalDateTime.now(),null
                    }
                    , MQConst.GalaxyQueue.SQL_SERIES_INFO.getKey()
            );
        }catch(Exception e){
            log.error(e.getMessage(),e);
            log.error("#setSeriesInfoBo error ==> MESSAGE:{}",e.getMessage());
        }
    }

    public GalaxySeriesInfoBo getSeriesInfoBo(String routerType, String seriesCode) {
        Object obj = redisUtil.get(GalaxyConstant.REDIS_KEY_GALAXY_SERIES.concat(routerType).concat(":") + seriesCode);
        if(obj!=null){
            return (GalaxySeriesInfoBo) obj;
        }else {
            GalaxySeriesInfoVo seriesInfoVo = mongoTemplate.findOne(Query.query(Criteria.where("seriesCode").is(seriesCode)), GalaxySeriesInfoVo.class, GalaxySeriesInfoVo.class.getSimpleName());
            if (seriesInfoVo == null) {
                return null;
            }
            GalaxySeriesInfoBo seriesInfoBo = GalaxySeriesInfoBo.getNew();
            BeanUtil.copy(seriesInfoVo,seriesInfoBo);
            redisUtil.set(GalaxyConstant.REDIS_KEY_GALAXY_SERIES.concat(routerType).concat(":") + seriesCode, seriesInfoBo);
            return seriesInfoBo;
        }
    }

    public void setSeriesNftInfoBo(String routerType, String skuId, GalaxySeriesInfoBo seriesInfoBo, GalaxySeriesNftInfoBo seriesNftInfoBo) {
        redisUtil.set(GalaxyConstant.REDIS_KEY_GALAXY_SERIES_NFT.concat(routerType).concat(":") + skuId,seriesNftInfoBo,keyExpireTime);

        //mongo入库
        GalaxySeriesNftInfoVo seriesNftInfoVo = GalaxySeriesNftInfoVo.getNew();
        BeanUtil.copy(seriesNftInfoBo,seriesNftInfoVo);
        seriesNftInfoVo.setCreatedAt(LocalDateTime.now());
        mongoTemplate.save(seriesNftInfoVo,GalaxySeriesNftInfoVo.class.getSimpleName());

        try{
//            insert into galaxy_series_nft_info (mid, series_nft_info_id, series_info_id, sku_id, series_name, series_code
//                    ,series_id, nft_total_count, nft_crt_count,nft_id_begin,original_nft_url
//                    , original_display_url,author, nft_name, nft_url, display_url
//                    , nft_desc, nft_flag, sell_count, nft_hash,router_type
//                    , created_at, updated_at)
            queueUtil.sendMySqlRedis(
                    SqlMapping.get("galaxy_series_nft_info.insert"),
                    new Object[]{seriesNftInfoBo.getSeriesNftInfoId(),seriesInfoBo.getSeriesInfoId(),skuId,seriesInfoBo.getSeriesName(),seriesInfoBo.getSeriesCode()
                            ,seriesInfoBo.getSeriesId(),seriesInfoBo.getTotalCount(),seriesInfoBo.getCrtCount(),seriesNftInfoBo.getNftIdBegin(),seriesNftInfoBo.getOriginalNftUrl()
                            ,seriesNftInfoBo.getOriginalDisplayUrl(),seriesNftInfoBo.getAuthor(),seriesNftInfoBo.getNftName(),seriesNftInfoBo.getNftUrl(),seriesNftInfoBo.getDisplayUrl()
                            ,seriesNftInfoBo.getNftDesc(),seriesNftInfoBo.getNftFlag(),seriesNftInfoBo.getSellCount(),seriesNftInfoBo.getNftHash(),seriesInfoBo.getRouterType()
                            ,LocalDateTime.now(),null
                    }
                    , MQConst.GalaxyQueue.SQL_SERIES_INFO.getKey());
        }catch(Exception e){
            log.error(e.getMessage(),e);
            log.error("#setSeriesInfoBo error ==> MESSAGE:{}",e.getMessage());
        }
    }


    public GalaxySeriesNftInfoBo getSeriesNftInfoBo(String routerType, String skuId) {
        Object obj = redisUtil.get(GalaxyConstant.REDIS_KEY_GALAXY_SERIES_NFT.concat(routerType).concat(":") + skuId);
        if(obj!=null){
            return (GalaxySeriesNftInfoBo) obj;
        }else {
            GalaxySeriesNftInfoVo seriesNftInfoVo = mongoTemplate.findOne(Query.query(Criteria.where("skuId").is(skuId)), GalaxySeriesNftInfoVo.class, GalaxySeriesNftInfoVo.class.getSimpleName());
            if (seriesNftInfoVo == null) {
                return null;
            }
            GalaxySeriesNftInfoBo seriesNftInfoBo = GalaxySeriesNftInfoBo.getNew();
            BeanUtil.copy(seriesNftInfoVo,seriesNftInfoBo);
            redisUtil.set(GalaxyConstant.REDIS_KEY_GALAXY_SERIES_NFT.concat(routerType).concat(":") + skuId, seriesNftInfoBo);
            return seriesNftInfoBo;
        }
    }

    public void updateSeriesClaimStatus(String routerType,String seriesCode, GalaxySeriesInfoBo seriesInfoBo) {
        redisUtil.set(GalaxyConstant.REDIS_KEY_GALAXY_SERIES.concat(routerType).concat(":") + seriesCode,seriesInfoBo,keyExpireTime);

        Query query = Query.query(Criteria.where("seriesCode").is(seriesInfoBo.getSeriesCode()));
        Update update = Update.fromDocument(Document.parse(JsonUtils.toJson(seriesInfoBo)));
        String nowTimeStr = DateUtil.Formatter.yyyyMMddHHmmss.format(LocalDateTime.now());
        update.set("updatedAt",nowTimeStr);
        UpdateResult result = mongoTemplate.updateFirst(query,update, GalaxySeriesInfoVo.class,GalaxySeriesInfoVo.class.getSimpleName());
        log.info("updateSeriesClaimStatus result:{}",result.toString());

        try{
            queueUtil.sendMySqlRedis(
                    SqlMapping.get("galaxy_series_info.updateSeriesIdAndStatus"),
                    new Object[]{seriesInfoBo.getSeriesId(),seriesInfoBo.getChainTimestamp(),seriesInfoBo.getTradeHash(),seriesInfoBo.getSeriesClaimStatus(),nowTimeStr,seriesInfoBo.getSeriesCode()}
                    , MQConst.GalaxyQueue.SQL_SERIES_INFO.getKey()
            );
        }catch(Exception e){
            log.error(e.getMessage(),e);
            log.error("#updateSeriesClaimStatus error ==> MESSAGE:{}",e.getMessage());
        }
        //更新系列对应的系列nft状态
        List<String> skuIdList = this.getSkuIdListBySeriesCode(seriesCode);
        skuIdList.stream().forEach(skuId -> {
            GalaxySeriesNftInfoBo seriesNftInfoBo = this.getSeriesNftInfoBo(routerType,skuId);
            seriesNftInfoBo.setSeriesId(seriesInfoBo.getSeriesId());
            seriesNftInfoBo.setUpdatedAt(LocalDateTime.now());
            this.updateSeriesNftStatus(routerType,skuId,seriesNftInfoBo);
        });
    }

    public void updateSeriesNftStatus(String routerType,String skuId, GalaxySeriesNftInfoBo seriesNftInfoBo) {
        //更新系列nft状态
        redisUtil.set(GalaxyConstant.REDIS_KEY_GALAXY_SERIES_NFT.concat(routerType).concat(":") + skuId,seriesNftInfoBo,keyExpireTime);

        Query query = Query.query(Criteria.where("skuId").is(skuId));
        Update update = Update.fromDocument(Document.parse(JsonUtils.toJson(seriesNftInfoBo)));
        String nowTimeStr = DateUtil.Formatter.yyyyMMddHHmmss.format(seriesNftInfoBo.getUpdatedAt());
        update.set("routerType",routerType);
        update.set("updatedAt",nowTimeStr);
        UpdateResult result = mongoTemplate.updateFirst(query,update, GalaxySeriesNftInfoVo.class,GalaxySeriesNftInfoVo.class.getSimpleName());
        log.info("updateSeriesNftStatus result:{}",result.toString());

        try{
            queueUtil.sendMySqlRedis(
                    SqlMapping.get("galaxy_series_nft_info.updateSeriesIdAndStatus"),
                    new Object[]{seriesNftInfoBo.getSeriesId(),nowTimeStr,seriesNftInfoBo.getSkuId()}
                    , MQConst.GalaxyQueue.SQL_SERIES_INFO.getKey()
            );
        }catch(Exception e){
            log.error(e.getMessage(),e);
            log.error("#updateSeriesNftStatus error ==> MESSAGE:{}",e.getMessage());
        }
    }

    //根据系列Id获取
    public List<String> getSkuIdListBySeriesCode(String seriesCode){
        //根据演出id获取用户信息 只查询5条
        List<String> skuIdList = new ArrayList<>();
        //获取总数
        Criteria criteria = Criteria.where("seriesCode").is(seriesCode);

        Query query = Query.query(criteria);

        long startTime = System.currentTimeMillis();
        List<GalaxySeriesNftInfoVo> seriesNftInfoVoList = mongoTemplate.find(query, GalaxySeriesNftInfoVo.class, GalaxySeriesNftInfoVo.class.getSimpleName());
        long endTime = System.currentTimeMillis();
        log.info("getSkuIdListBySeriesCode 根据系列code获取skuId 耗时：{}ms",endTime-startTime);

        //根据用户id获取头像信息
        if(StringUtil.isNotNull(seriesNftInfoVoList)){
            skuIdList = seriesNftInfoVoList.stream().map(GalaxySeriesNftInfoVo::getSkuId).collect(Collectors.toList());
        }
        return skuIdList;
    }

    public void setNftOrderBo(String routerType,String nftOrderPayId, GalaxyNftOrderBo nftOrderBo) {

        redisUtil.set(GalaxyConstant.REDIS_KEY_GALAXY_TRADE.concat(routerType).concat(":") + nftOrderPayId,nftOrderBo,keyExpireTime);
        /**
         * 入库mongo
         */
        GalaxyNftOrderVo nftOrderVo = GalaxyNftOrderVo.getNew();
        BeanUtil.copy(nftOrderBo,nftOrderVo);
        mongoTemplate.save(nftOrderVo,GalaxyNftOrderVo.class.getSimpleName());

//        insert into galaxy_nft_order_info (mid, nft_order_pay_id, user_id, sku_id, series_name, series_id
//                , nft_id, nft_price,from_address, to_address, nft_publish_task_id, nft_buy_task_id
//                , nft_buy_pay_task_id,router_type, created_at, updated_at)
        try{
            queueUtil.sendMySqlRedis(
                    SqlMapping.get("galaxy_nft_order_info.insert"),
                    new Object[]{nftOrderPayId,nftOrderBo.getUserId(),nftOrderBo.getSkuId(),nftOrderBo.getSeriesName(),nftOrderBo.getSeriesId()
                            ,nftOrderBo.getNftId(),nftOrderBo.getNftPrice(),nftOrderBo.getFromAddress(),nftOrderBo.getToAddress(),nftOrderBo.getNftPublishTaskId()
                            ,nftOrderBo.getNftBuyTaskId(),nftOrderBo.getNftBuyPayTaskId(),nftOrderBo.getRouterType(),LocalDateTime.now(),null
                    }
                    , MQConst.GalaxyQueue.SQL_NFT_ORDER_INFO.getKey()
            );
        }catch(Exception e){
            log.error(e.getMessage(),e);
            log.error("#setNftOrderBo error ==> MESSAGE:{}",e.getMessage());
        }
    }

    public GalaxyNftOrderBo getNftOrderBo(String routerType, String nftOrderPayId) {
        Object obj = redisUtil.get(GalaxyConstant.REDIS_KEY_GALAXY_TRADE.concat(routerType).concat(":") + nftOrderPayId);
        if(obj!=null){
            return (GalaxyNftOrderBo) obj;
        }else {
            GalaxyNftOrderVo nftOrderVo = mongoTemplate.findOne(Query.query(Criteria.where("nftOrderPayId").is(nftOrderPayId)), GalaxyNftOrderVo.class, GalaxyNftOrderVo.class.getSimpleName());
            if (nftOrderVo == null) {
                return null;
            }
            GalaxyNftOrderBo nftOrderBo = GalaxyNftOrderBo.getNew();
            BeanUtil.copy(nftOrderVo,nftOrderBo);
            redisUtil.set(GalaxyConstant.REDIS_KEY_GALAXY_TRADE.concat(routerType).concat(":") + nftOrderPayId, nftOrderBo);
            return nftOrderBo;
        }
    }

    public void updateNftOrderInfo(String routerType,String nftOrderPayId,GalaxyNftOrderBo nftOrderBo) {
        redisUtil.set(GalaxyConstant.REDIS_KEY_GALAXY_TRADE.concat(routerType).concat(":") + nftOrderPayId,nftOrderBo,keyExpireTime);

        Query query = Query.query(Criteria.where("nftOrderPayId").is(nftOrderBo.getNftOrderPayId()));
        Update update = Update.fromDocument(Document.parse(JsonUtils.toJson(nftOrderBo)));
        update.set("nftId", nftOrderBo.getNftId());
        String nowTimeStr = DateUtil.Formatter.yyyyMMddHHmmss.format(LocalDateTime.now());
        update.set("updatedAt",nowTimeStr);
        UpdateResult result = mongoTemplate.updateFirst(query,update, GalaxyNftOrderVo.class,GalaxyNftOrderVo.class.getSimpleName());
        log.info("updateNftOrderInfo result:{}",result.toString());

        try{
            queueUtil.sendMySqlRedis(
                    SqlMapping.get("galaxy_nft_order_info.updateNftId"),
                    new Object[]{nftOrderBo.getNftId(),LocalDateTime.now(),nftOrderBo.getNftOrderPayId()}
                    , MQConst.GalaxyQueue.SQL_NFT_TRADE_INFO.getKey()
            );
        }catch(Exception e){
            log.error(e.getMessage(),e);
            log.error("#setNftTradeInfo error ==> MESSAGE:{}",e.getMessage());
        }
    }

    public void updateNftOrderBuyTaskId(String routerType,String nftOrderPayId,GalaxyNftOrderBo nftOrderBo) {
        redisUtil.set(GalaxyConstant.REDIS_KEY_GALAXY_TRADE.concat(routerType).concat(":") + nftOrderPayId,nftOrderBo,keyExpireTime);

        Query query = Query.query(Criteria.where("nftOrderPayId").is(nftOrderPayId));
        Update update = Update.fromDocument(Document.parse(JsonUtils.toJson(nftOrderBo)));
        update.set("nftBuyTaskId", nftOrderBo.getNftBuyTaskId());
        String nowTimeStr = DateUtil.Formatter.yyyyMMddHHmmss.format(LocalDateTime.now());
        update.set("updatedAt",nowTimeStr);
        UpdateResult result = mongoTemplate.updateFirst(query,update, GalaxyNftOrderVo.class,GalaxyNftOrderVo.class.getSimpleName());
        log.info("updateNftOrderInfo result:{}",result.toString());

        try{
            queueUtil.sendMySqlRedis(
                    SqlMapping.get("galaxy_nft_order_info.updateNftBuyTaskId"),
                    new Object[]{nftOrderBo.getNftBuyTaskId(),LocalDateTime.now(),nftOrderBo.getNftOrderPayId()}
                    , MQConst.GalaxyQueue.SQL_NFT_TRADE_INFO.getKey()
            );
        }catch(Exception e){
            log.error(e.getMessage(),e);
            log.error("#setNftTradeInfo error ==> MESSAGE:{}",e.getMessage());
        }
    }

    public void setNftTradeInfo(String routerType, GalaxyNftTradeVo nftTradeVo) {
        /**
         * 入库mongo
         */
        mongoTemplate.save(nftTradeVo,GalaxyNftTradeVo.class.getSimpleName());

//        insert into galaxy_nft_trade_info (mid, nft_id, series_id, trade_hash, chain_timestamp, from_address
//        , to_address,trade_price, trade_type, created_at, updated_at)
        try{
            queueUtil.sendMySqlRedis(
                    SqlMapping.get("galaxy_nft_trade_info.insert"),
                    new Object[]{nftTradeVo.getNftId(),nftTradeVo.getSeriesId(),nftTradeVo.getTradeHash(),nftTradeVo.getChainTimestamp(),nftTradeVo.getFromAddress()
                            ,nftTradeVo.getToAddress(),nftTradeVo.getTradePrice(),nftTradeVo.getTradeType(),LocalDateTime.now(),null
                    }
                    , MQConst.GalaxyQueue.SQL_NFT_TRADE_INFO.getKey()
            );
        }catch(Exception e){
            log.error(e.getMessage(),e);
            log.error("#setNftTradeInfo error ==> MESSAGE:{}",e.getMessage());
        }
    }

}
