package com.liquidnet.service.galaxy.router.zxin.biz;

import com.liquidnet.common.third.zxlnft.biz.ZxlnftBiz;
import com.liquidnet.common.third.zxlnft.constant.ZxlErrorEnum;
import com.liquidnet.common.third.zxlnft.dto.*;
import com.liquidnet.common.third.zxlnft.dto.nft.Nft016QueryRsData;
import com.liquidnet.common.third.zxlnft.dto.wallet.CreateMnemonicReq;
import com.liquidnet.common.third.zxlnft.dto.wallet.CreateMnemonicResp;
import com.liquidnet.common.third.zxlnft.dto.wallet.DeriveKeyPairReq;
import com.liquidnet.common.third.zxlnft.dto.wallet.DeriveKeyPairResp;
import com.liquidnet.common.third.zxlnft.exception.ZxlNftException;
import com.liquidnet.common.third.zxlnft.util.ZxlWalletSdkUtil;
import com.liquidnet.common.third.zxlnft.util.ZxlnftSdkUtil;
import com.liquidnet.commons.lang.util.*;
import com.liquidnet.service.adam.constant.AdamEnum;
import com.liquidnet.service.base.ResponseDto;
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.constant.GalaxyErrorEnum;
import com.liquidnet.service.galaxy.dto.bo.GalaxyUserInfoBo;
import com.liquidnet.service.galaxy.dto.param.GalaxyUserRegisterReqDto;
import com.liquidnet.service.galaxy.dto.param.GalaxyUserRegisterRespDto;
import com.liquidnet.service.galaxy.exception.GalaxyNftUserException;
import com.liquidnet.service.galaxy.router.xuper.biz.XuperUserCommonBiz;
import com.liquidnet.service.galaxy.utils.GalaxyDataUtils;
import com.liquidnet.service.goblin.constant.GoblinRedisConst;
import com.liquidnet.service.goblin.constant.NftAccStatusEnum;
import com.liquidnet.service.goblin.dto.GoblinUserNftAccInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;
import java.time.LocalDateTime;
import java.util.LinkedList;
import java.util.List;

/**
 * @author AnJiabin <anjiabin@zhengzai.tv>
 * @version V1.0
 * @Description: TODO
 * @class: ZxinUserCommonBiz
 * @Package com.liquidnet.service.galaxy.router.zxin.biz
 * @Copyright: LightNet @ Copyright (c) 2021
 * @date 2022/5/12 13:08
 */
@Slf4j
@Component
public class ZxinUserCommonBiz {
    @Autowired
    private ZxlnftSdkUtil zxlnftSdkUtil;

    @Autowired
    private ZxlnftBiz zxlnftBiz;

    @Autowired
    private GalaxyDataUtils dataUtils;

    @Autowired
    private ZxlWalletSdkUtil zxlWalletSdkUtil;

    @Value("${liquidnet.service.adam.url}")
    private String adamUrl;

    @Autowired
    private XuperUserCommonBiz xuperUserCommonBiz;

    public ResponseDto<GalaxyUserRegisterRespDto> userRegister(GalaxyUserRegisterReqDto reqDto) {
        long startTime = System.currentTimeMillis();
        String userId = reqDto.getUserId();
        String userName = reqDto.getUserName();
        String mobile = reqDto.getMobile();
        String idCardType = reqDto.getIdCardType();
        String idCard = reqDto.getIdCard();
        String mnemonic = null;
        Long index = 0L;
        String userIdentification = null;
        String address = null;
        String userPubKey = null;
        String userPriKey = null;

        //业务失败信息
        String bizFailDesc = null;
        //系统失败信息
        String sysFailDesc = null;
        //是否实名认证成功
        boolean isRealNameAuthSuccess = false;
        //是否绑定区块链地址
        boolean isBindBlockAddressSuccess = false;
        GalaxyUserRegisterRespDto respDto = GalaxyUserRegisterRespDto.getNew();

        //用户信息
        GalaxyUserInfoBo userInfoBo = null;
        try{
            /**
             * todo 把助记词进行redis存储  key=userID  mnemonic/index/userIdentification/address
             */
            userInfoBo = dataUtils.getGalaxyUserInfo(reqDto.getRouterType(),userId);
            if(userInfoBo!=null){
                mnemonic = userInfoBo.getMnemonic();
                if(StringUtil.isNotEmpty(userInfoBo.getBlockChainAddress())){
                    try{
                        //同步用户数字账户开通信息
                        boolean isOpenAccount = syncOpenAccount(reqDto,respDto.getBlockChainAddress(),bizFailDesc,sysFailDesc,true,true);
                        log.info("用户 {} 数字账户开通结果:{}",reqDto.getUserId(),isOpenAccount);
                    }catch(Exception e){
                        log.error("同步用户数字账户开通信息异常："+e.getMessage(),e);
                    }
                    return ResponseDto.failure("已经开通过数字账户");
                }
            }else{
                try{
                    //生成助记词
                    CreateMnemonicReq req = CreateMnemonicReq.getNew();
                    CreateMnemonicResp createMnemonicResp = zxlWalletSdkUtil.createMnemonic(req);
                    mnemonic = createMnemonicResp.getMnemonic();
                }catch(Exception e){
                    log.error("生成助记词失败 msg：{}",e.getMessage(),e);
                    throw new ZxlNftException(ZxlErrorEnum.FAILURE.getCode(),"生成助记词失败！");
                }
            }
            if(StringUtil.isNotEmpty(mnemonic)){
                //生成公私钥
                DeriveKeyPairReq deriveKeyPairReq = DeriveKeyPairReq.getNew();
                deriveKeyPairReq.setMnemonic(mnemonic);
//        deriveKeyPairReq.setMnemonic(createMnemonicResp.getMnemonic());
                deriveKeyPairReq.setIndex(index);
                try{
                    DeriveKeyPairResp deriveKeyPairResp = zxlWalletSdkUtil.deriveKeyPair(deriveKeyPairReq);
                    if(!deriveKeyPairResp.getErr().equals("")) throw new Exception("生成公私钥失败！");
                    userPubKey = BASE64Util.encoded(deriveKeyPairResp.getPubKey());
                    userPriKey = BASE64Util.encoded(deriveKeyPairResp.getPriKey());
                }catch(Exception e){
                    log.error("生成公私钥失败 msg：{}",e.getMessage(),e);
                    throw new ZxlNftException(ZxlErrorEnum.FAILURE.getCode(),e.getMessage());
                }
            }

            if(StringUtil.isNull(userInfoBo)){
                //初始化用户信息
                try{
                    //构造缓存数据
                    userInfoBo = GalaxyUserInfoBo.getNew();
                    userInfoBo.setUserId(userId);
                    userInfoBo.setUserName(userName);
                    userInfoBo.setMobile(mobile);
                    userInfoBo.setIdCardType(idCardType);
                    userInfoBo.setIdCard(idCard);
                    userInfoBo.setMnemonic(mnemonic);
                    userInfoBo.setIndex(index.toString());
                    userInfoBo.setUserIdentification(userIdentification);
                    userInfoBo.setUserPubKey(userPubKey);
                    userInfoBo.setUserPriKey(userPriKey);
                    userInfoBo.setRouterType(GalaxyEnum.RouterTypeEnum.ZXINCHAIN.getCode());
                    userInfoBo.setBlockChainAddress(address);
                    dataUtils.setGalaxyUserInfo(reqDto.getRouterType(),reqDto.getUserId(),userInfoBo);
                }catch(Exception e){
                    log.error("设置用户信息异常 msg：{}",e.getMessage(),e);
                    throw new ZxlNftException(ZxlErrorEnum.FAILURE.getCode(),"设置用户信息异常");
                }
            }

            //1.2.1调用自然人注册实名(使用NFT平台签名)接口
            Nft003RegisterPersonPlatformReqDto nft003ReqDto = Nft003RegisterPersonPlatformReqDto.getNew();
            nft003ReqDto.setPersonName(userName);
//        reqDto.setEmail("");
            nft003ReqDto.setMobile(mobile);
            nft003ReqDto.setIdCard(idCard);

            nft003ReqDto.setCardType(Integer.valueOf(idCardType));
            ZxlnftResponseDto<Nft003RegisterPersonPlatformRespDto> nft003Resp = zxlnftSdkUtil.nft003RegisterPersonPlatform(nft003ReqDto);

            if(nft003Resp.isSuccess()){
                userIdentification = nft003Resp.getData().getUserIdentification();
                isRealNameAuthSuccess = true;
            }else{
                if(nft003Resp.getCode().equals(ZxlErrorEnum.SERVER_INNER_ERROR.getCode())){
                    throw new ZxlNftException(nft003Resp.getCode(),nft003Resp.getMessage());
                }else{
                    throw new GalaxyNftUserException(nft003Resp.getCode(),nft003Resp.getMessage());
                }
            }

            //如果实名认证成功，并且该身份证已经开通过数字账户
            if(isRealNameAuthSuccess){
                String blockAddress = dataUtils.getGalaxyUserInfoByIdCardNo(reqDto.getRouterType(),idCard);
                if(StringUtil.isNotEmpty(blockAddress)){
                    throw new GalaxyNftUserException(GalaxyErrorEnum.NFT_USER_HAS_OPEN_ACCOUNT.getCode(),GalaxyErrorEnum.NFT_USER_HAS_OPEN_ACCOUNT.getMessage());
                }
            }

            if(StringUtil.isNotEmpty(userPubKey)&&StringUtil.isNotEmpty(userPriKey)&&StringUtil.isNotEmpty(userIdentification)){
                //1.2.2调用授信平台NFT地址绑定接口
                Nft014IdentityBindSubmitByTrustedReqDto nft014ReqDto = Nft014IdentityBindSubmitByTrustedReqDto.getNew();

                try {
                    nft014ReqDto.setUserPubKey(BASE64Util.decode(userPubKey));
                    nft014ReqDto.setUserIdentification(nft003Resp.getData().getUserIdentification());

                    String signature = zxlnftBiz.createSign(BASE64Util.decode(userPriKey),nft014ReqDto.getUserIdentification());
                    nft014ReqDto.setUserSignData(signature);
                } catch (UnsupportedEncodingException e) {
                    log.error("公私钥解密错误！");
                    throw new ZxlNftException(ZxlErrorEnum.FAILURE.getCode(),e.getMessage());
                }

                ZxlnftResponseDto<Nft014IdentityBindSubmitByTrustedRespDto> nft014Resp = zxlnftSdkUtil.nft014IdentityBindSubmitByTrusted(nft014ReqDto);

                ZxlnftResponseDto<Nft016IdentityBindQueryRespDto> nft016Resp = null;
                if(nft014Resp.isSuccess()){
                    //1.2.3调用绑定状态批量查询
                    Nft016IdentityBindQueryReqDto nft016ReqDto = Nft016IdentityBindQueryReqDto.getNew();
                    nft016ReqDto.setAddressList(nft014Resp.getData().getAddress());
                    nft016Resp = zxlnftSdkUtil.nft016IdentityBindQuery(nft016ReqDto);
                }else{
                    log.info("nft014Resp 返回结果：{}",nft014Resp.toJson());
                    throw new GalaxyNftUserException(nft014Resp.getCode(),nft014Resp.getMessage());
                }

                if(StringUtil.isNotNull(nft016Resp)&&nft016Resp.isSuccess()){
                    List<Nft016QueryRsData> queryRsDataList =  nft016Resp.getData().getList();
                    Nft016QueryRsData queryRsData = queryRsDataList.get(0);
                    address = queryRsData.getAddress();
                    log.info("nft016Resp 返回结果：{}",nft016Resp.toJson());
                    //构造返回参数
                    respDto.setUserId(userId);
                    respDto.setBlockChainType(GalaxyEnum.RouterTypeEnum.ZXINCHAIN.getCode());
                    respDto.setBlockChainAddress(address);

                    isBindBlockAddressSuccess = true;
                    userInfoBo.setBlockChainAddress(address);

                    //设置
                    dataUtils.setGalaxyUserInfoByIdCardNo(reqDto.getRouterType(),idCard,address);
                }else{
                    throw new GalaxyNftUserException(nft016Resp.getCode(),nft016Resp.getMessage());
                }
            }
        }catch (GalaxyNftUserException e) {
            bizFailDesc = e.getMessage();
            log.info(e.getMessage());
        }catch(ZxlNftException e){
            sysFailDesc = e.getMessage();
            log.error(e.getMessage(),e);
        }catch(Exception e){
            sysFailDesc = e.getMessage();
            log.error(e.getMessage(),e);
        }

        //如果实名认证成功-更新数据库
        if(isRealNameAuthSuccess){
            if(StringUtil.isNotNull(userInfoBo)){
                userInfoBo.setUserName(userName);
                userInfoBo.setMobile(mobile);
                userInfoBo.setIdCardType(idCardType);
                userInfoBo.setIdCard(idCard);
                userInfoBo.setUserIdentification(userIdentification);
                dataUtils.updateGalaxyUserInfo(reqDto.getRouterType(),reqDto.getUserId(),userInfoBo);
            }
        }

        try{
            //同步用户数字账户开通信息
            boolean isOpenAccount = syncOpenAccount(reqDto,respDto.getBlockChainAddress(),bizFailDesc,sysFailDesc,isRealNameAuthSuccess,isBindBlockAddressSuccess);
            log.info("用户 {} 数字账户开通结果:{}",reqDto.getUserId(),isOpenAccount);
        }catch(Exception e){
            log.error("同步用户数字账户开通信息异常："+e.getMessage(),e);
        }

        long endTime = System.currentTimeMillis();
        log.info("开通数字账户userRegister总耗时:{} ",endTime-startTime);

        if(StringUtil.isNotEmpty(sysFailDesc)){
            return ResponseDto.failure(sysFailDesc);
        }
        if(StringUtil.isNotEmpty(bizFailDesc)){
            return ResponseDto.failure(bizFailDesc);
        }
        return ResponseDto.success(respDto);
    }


    /**
     * 同步用户数字账户开通信息
     * @param reqDto
     * @param bizFailDesc
     * @param sysFailDesc
     * @param isRealNameAuthSuccess
     * @param isBindBlockAddressSuccess
     * @return
     */
    public boolean syncOpenAccount(GalaxyUserRegisterReqDto reqDto,String blockChainAddress,String bizFailDesc,String sysFailDesc,
                                   boolean isRealNameAuthSuccess,boolean isBindBlockAddressSuccess){
        long startTime = System.currentTimeMillis();
        long openAccSuccessKeyExpireTime = 3600*24*30*3;
        long openAccFailKeyExpireTime = 60*5;

        //是否开通数字账户
        boolean isOpenAccount = false;
        //开通失败错误信息
        String resultCode = NftAccStatusEnum.StatusAcc.ING.getCode();
        String resultMessage = NftAccStatusEnum.StatusAcc.ING.getMsg();

        //百度链开通数字账户
        boolean isOpenXuperUserSuccess = false;
        if(isRealNameAuthSuccess && isBindBlockAddressSuccess){
            ResponseDto<GalaxyUserRegisterRespDto> xuperUserRegisterRespDto = this.isOpenXuperUserSuccess(reqDto);;
            if(xuperUserRegisterRespDto.isSuccess()){
                isOpenXuperUserSuccess = true;
            }
        }

        //实名成功+绑定区块链地址成功
        if(isRealNameAuthSuccess && isBindBlockAddressSuccess && isOpenXuperUserSuccess){
            isOpenAccount = true;
            resultCode = NftAccStatusEnum.StatusAcc.SUCCESS.getCode();
            resultMessage = NftAccStatusEnum.StatusAcc.SUCCESS.getMsg();
        }

        //开通数字账户失败
        if(!isOpenAccount){
            //实名失败
            if(!isRealNameAuthSuccess){
                if(StringUtil.isNotEmpty(bizFailDesc)){
                    resultCode = NftAccStatusEnum.StatusAcc.FAILURE1.getCode();
                    resultMessage = NftAccStatusEnum.StatusAcc.FAILURE1.getMsg();
                }else if(StringUtil.isNotEmpty(sysFailDesc)){
                    resultCode = NftAccStatusEnum.StatusAcc.FAILURE2.getCode();
                    resultMessage = NftAccStatusEnum.StatusAcc.FAILURE2.getMsg();
                }
            }else{
                //地址绑定失败
                if(!isBindBlockAddressSuccess){
                    if(StringUtil.isNotEmpty(bizFailDesc)){
                        resultCode = NftAccStatusEnum.StatusAcc.FAILURE3.getCode();
                        resultMessage = NftAccStatusEnum.StatusAcc.FAILURE3.getMsg();
                    }else if(StringUtil.isNotEmpty(sysFailDesc)){
                        resultCode = NftAccStatusEnum.StatusAcc.FAILURE2.getCode();
                        resultMessage = NftAccStatusEnum.StatusAcc.FAILURE2.getMsg();
                    }
                }else if(!isOpenXuperUserSuccess){
                    resultCode = NftAccStatusEnum.StatusAcc.FAILURE2.getCode();
                    resultMessage = NftAccStatusEnum.StatusAcc.FAILURE2.getMsg();
                }
            }
        }

        //更新至信链开户状态
        GoblinUserNftAccInfoVo goblinUserNftAccInfoVo = GoblinUserNftAccInfoVo.getNew();
        goblinUserNftAccInfoVo.setCode(resultCode);
        goblinUserNftAccInfoVo.setMsg(resultMessage);
        goblinUserNftAccInfoVo.setTime(LocalDateTime.now());

        if(isOpenAccount){
            //更新开户状态
            dataUtils.getRedisUtil().set(GoblinRedisConst.REDIS_GOBLIN_NFT_NUM_ACCOUNT_INFO.concat(reqDto.getUserId())
                    ,goblinUserNftAccInfoVo);

            //同步用户信息到adam 格式：{uid},{mobile},{证件类型}{证件号},{姓名}
            syncUserAccountInfoToAdam(reqDto);

            //同步业务账号关联关系到adam
            LinkedList<Object[]> sqlsDataA = CollectionUtil.linkedListObjectArr();
            sqlsDataA.add(new Object[]{
                    reqDto.getUserId(), AdamEnum.BizAcct.NFT_ZX.name(), blockChainAddress, null, null, 1, LocalDateTime.now()
            });
            sqlsDataA.add(new Object[]{
                    reqDto.getUserId(), AdamEnum.BizAcct.NFT_XUPER.name(), xuperUserRegisterRespDto.getData().getBlockChainAddress(), null, null, 1, LocalDateTime.now()
            });
            dataUtils.getQueueUtil().sendMsgByRedis(MQConst.GoblinQueue.SQL_STORE.getKey(),
                    SqlMapping.get("adam_user_busi_acct.add",sqlsDataA)
            );

            //开户成功记录缓存 {goblin:nft:certmeta:{idType+idNo},{idname,mobile}}
            dataUtils.getRedisUtil().set(GoblinRedisConst.REDIS_GOBLIN_NFT_CERTMETA.concat(reqDto.getIdCardType().concat(reqDto.getIdCard()))
                    ,reqDto.getUserName().concat(",").concat(reqDto.getMobile()),openAccSuccessKeyExpireTime);
        }else{
            //更新开户状态
            dataUtils.getRedisUtil().set(GoblinRedisConst.REDIS_GOBLIN_NFT_NUM_ACCOUNT_INFO.concat(reqDto.getUserId())
                    ,goblinUserNftAccInfoVo);
        }

        //设置错误信息到redis
        if(StringUtil.isNotEmpty(resultCode)&&resultCode.equalsIgnoreCase(NftAccStatusEnum.StatusAcc.FAILURE1.getCode())){
            //开户失败记录缓存 {goblin:nft:certmeta:{idType+idNo},{idname,mobile}}
            dataUtils.getRedisUtil().set(GoblinRedisConst.REDIS_GOBLIN_NFT_CERTMETA_JUNK.concat(reqDto.getIdCardType().concat(reqDto.getIdCard()))
                    ,reqDto.getUserName().concat(",").concat(reqDto.getMobile()),openAccFailKeyExpireTime);
        }
        long endTime = System.currentTimeMillis();
        log.info("同步数字账户syncOpenAccount总耗时:{} ",endTime-startTime);
        return isOpenAccount;
    }

    /**
     * 同步用户信息到adam 格式：{uid},{mobile},{证件类型}{证件号},{姓名}
     * @param reqDto
     * @return
     */
    private boolean syncUserAccountInfoToAdam(GalaxyUserRegisterReqDto reqDto) {
        try {
            String certmetaInfo = reqDto.getUserId().concat(",")
                    .concat(reqDto.getMobile()).concat(",")
                    .concat(reqDto.getIdCardType().concat(reqDto.getIdCard())).concat(",")
                    .concat(reqDto.getUserName());
            //加密用户信息
            DESUtils desUtils = DESUtils.DES();
//            MultiValueMap<String, String> params = new LinkedMultiValueMap();
//            params.add("certmeta",desUtils.encrypt(certmetaInfo));
//
//            HttpUtil.post(adamUrl + GalaxyConstant.ADAM_USER_SYNC_URL, params);
            HttpUtil.postJson(adamUrl + GalaxyConstant.ADAM_USER_SYNC_URL, desUtils.encrypt(certmetaInfo));
        } catch (Exception e) {
            log.error("同步用户信息到adam异常:{}", JsonUtils.toJson(reqDto), e);
            return false;
        }
        return true;
    }

    /**
     * 是否开通xuper数字账户
     * @param reqDto
     * @return
     */
    private ResponseDto<GalaxyUserRegisterRespDto> isOpenXuperUserSuccess(GalaxyUserRegisterReqDto reqDto){
        reqDto.setRouterType(GalaxyEnum.RouterTypeEnum.XUPER.getCode());
        return xuperUserCommonBiz.userRegister(reqDto);
    }

}
