package com.fzm.mall.server.admin.goods_center.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.fzm.mall.server.admin.block_chain.util.ChainUtil;
import com.fzm.mall.server.admin.constant.MALLGlobalConfig;
import com.fzm.mall.server.admin.constant.MallResponseError;
import com.fzm.mall.server.admin.exception.MyException;
import com.fzm.mall.server.admin.goods_center.entity.dto.NFTDTO;
import com.fzm.mall.server.admin.goods_center.entity.vo.GoodsNftVO;
import com.fzm.mall.server.admin.goods_center.model.ExternalToken;
import com.fzm.mall.server.admin.goods_center.model.GoodsNft;
import com.fzm.mall.server.admin.goods_center.mapper.GoodsNftMapper;
import com.fzm.mall.server.admin.goods_center.service.IExternalTokenService;
import com.fzm.mall.server.admin.goods_center.service.IGoodsNftService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fzm.mall.server.admin.mq.MsgProducer;
import com.fzm.mall.server.admin.mq.enums.QueueTTLTypeEnum;
import com.fzm.mall.server.admin.util.ObjectUtil;
import org.dozer.DozerBeanMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author fzm
 * @since 2021-08-30
 */
@Service
@Transactional
public class GoodsNftServiceImpl extends ServiceImpl<GoodsNftMapper, GoodsNft> implements IGoodsNftService {

    @Autowired
    private DozerBeanMapper beanMapper;
    @Autowired
    private IExternalTokenService externalTokenService;
    @Autowired
    private ChainUtil chainUtil;
    @Autowired
    private MsgProducer msgProducer;

    @Override
    public void add(NFTDTO nftdto, String goodsId, String name, String nftAddr, String merchantId, long timestamp) {
        ObjectUtil.checkObjFieldsIsNull(nftdto, "type", "tokenId");

        String tokenId = nftdto.getTokenId();
        String hash = "";
        if (nftdto.getTzType() != null && nftdto.getTzType().equals(1)) {
            //发行NFT
            hash = chainUtil.evmPublishTokenSplit(nftAddr, timestamp, nftdto.getNumber());

            Map<String, Object> map = new HashMap<>();
            map.put("goodsId", goodsId);
            map.put("hash", hash);
            msgProducer.sendTTL(map, QueueTTLTypeEnum.NFT_ISSUE_TTL, 10 * 1000);

            tokenId = MALLGlobalConfig.NFT_PREFIX + timestamp;
        }

        GoodsNft goodsNft = beanMapper.map(nftdto, GoodsNft.class);
        goodsNft.setGoodsId(goodsId);
//        goodsNft.setStock(nftdto.getNumber());
        goodsNft.setTokenId(tokenId);
        goodsNft.setHash(hash);
        save(goodsNft);

        if (nftdto.getTzType() != null && nftdto.getTzType().equals(2)) {
            boolean update = false;
            while (!update) {
                ExternalToken externalToken = externalTokenService.queryByLabelNameAndMerchantId(nftdto.getTokenId(), merchantId);
                if (externalToken.getStatus().equals(1)) {
                    throw new MyException(MallResponseError.TOKEN_HAS_BLINDING);
                }

                LambdaUpdateWrapper<ExternalToken> uw = new LambdaUpdateWrapper<>();
                uw.set(ExternalToken::getGoodsId, goodsId);
                uw.set(ExternalToken::getGoodsName, name);
                uw.set(ExternalToken::getStatus, 1);
                uw.set(ExternalToken::getBindNumber, externalToken.getAvailableNumber());
                uw.eq(ExternalToken::getLabelName, nftdto.getTokenId());
                uw.eq(ExternalToken::getMerchantId, merchantId);
                uw.eq(ExternalToken::getUpdateTime, externalToken.getUpdateTime());
                update = externalTokenService.update(uw);
            }
        }
    }

    @Override
    public void draft(NFTDTO nftdto, String goodsId) {
        GoodsNft nft = beanMapper.map(nftdto, GoodsNft.class);
        nft.setGoodsId(goodsId);
        save(nft);
    }

    @Override
    public GoodsNftVO getByGoodsId(String goodsId) {
        LambdaQueryWrapper<GoodsNft> qw = new LambdaQueryWrapper<>();
        qw.eq(GoodsNft::getGoodsId, goodsId);
        if (getOne(qw) == null)
            return null;
        return beanMapper.map(getOne(qw), GoodsNftVO.class);
    }

    @Override
    public GoodsNft getByGoodsIdInner(String goodsId) {
        LambdaQueryWrapper<GoodsNft> qw = new LambdaQueryWrapper<>();
        qw.eq(GoodsNft::getGoodsId, goodsId);
        return getOne(qw);
    }

    @Override
    public void edit(NFTDTO nftdto, String goodsId) {
        ObjectUtil.checkObjFieldsIsNull(nftdto, "type", "number", "tokenId");
        UpdateWrapper<GoodsNft> uw = new UpdateWrapper<>();
        uw.lambda().eq(GoodsNft::getGoodsId, goodsId);
        GoodsNft goodsNft = beanMapper.map(nftdto, GoodsNft.class);
        update(goodsNft, uw);
    }

    @Override
    public void republish(NFTDTO nftdto, String goodsId, String nftAddr) {
        /*ObjectUtil.checkObjFieldsIsNull(nftdto, "type", "number", "tokenId");

        String tokenId = nftdto.getTokenId();
        String hash = "";
        if (nftdto.getType().equals(1)) {
            //发行NFT
            tokenId = System.currentTimeMillis();
            hash = NftEvm.evmPublishToken(nftAddr, tokenId, nftdto.getNumber());
        }

        UpdateWrapper<GoodsNft> uw = new UpdateWrapper<>();
        uw.lambda().eq(GoodsNft::getGoodsId, goodsId);
        GoodsNft goodsNft = beanMapper.map(nftdto, GoodsNft.class);
        goodsNft.setStock(nftdto.getNumber());
        goodsNft.setTokenId(tokenId);
        goodsNft.setHash(hash);
        update(goodsNft, uw);*/
    }

    @Override
    public GoodsNft queryByTokenId(String tokenId) {
        QueryWrapper<GoodsNft> qw = new QueryWrapper<>();
        qw.lambda().eq(GoodsNft::getTokenId, tokenId);
        return getOne(qw);
    }

    @Override
    public void removeByGoodsId(String goodsId) {
        LambdaQueryWrapper<GoodsNft> qw = new LambdaQueryWrapper<>();
        qw.eq(GoodsNft::getGoodsId, goodsId);
        remove(qw);
    }
}
