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

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fzm.mall.server.admin.chain.FzmChain;
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.finance_center.entity.dto.*;
import com.fzm.mall.server.admin.finance_center.entity.vo.BaseIntegralDetailVO;
import com.fzm.mall.server.admin.finance_center.enums.status.PlatformIntegralStatusEnum;
import com.fzm.mall.server.admin.finance_center.enums.type.AssetsFlowTypeEnum;
import com.fzm.mall.server.admin.finance_center.enums.type.PlatformIntegralTypeEnum;
import com.fzm.mall.server.admin.finance_center.enums.type.TranObjectEnum;
import com.fzm.mall.server.admin.finance_center.mapper.PlatformIntegralMapper;
import com.fzm.mall.server.admin.finance_center.model.PlatformIntegral;
import com.fzm.mall.server.admin.finance_center.model.UserAsset;
import com.fzm.mall.server.admin.finance_center.service.IPlatformIntegralService;
import com.fzm.mall.server.admin.finance_center.service.IUserAssetService;
import com.fzm.mall.server.admin.home_page.model.Merchant;
import com.fzm.mall.server.admin.home_page.service.IMerchantService;
import com.fzm.mall.server.admin.mq.MsgProducer;
import com.fzm.mall.server.admin.mq.enums.QueueTTLTypeEnum;
import com.fzm.mall.server.admin.system.model.SysConfig;
import com.fzm.mall.server.admin.system.service.ISysConfigService;
import com.fzm.mall.server.admin.user_center.model.User;
import com.fzm.mall.server.admin.user_center.service.IUserService;
import com.fzm.mall.server.admin.util.ExcelUtil;
import com.fzm.mall.server.admin.util.OSSUtil;
import com.fzm.mall.server.admin.util.SerialIdsUtil;
import com.fzm.mall.server.admin.util.UUIDUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dozer.DozerBeanMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author wangp
 * @date 2021/4/27 10:44
 * @description 服务实现类
 * @since JDK 1.8
 */
@Slf4j
@Service
@Transactional
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class PlatformIntegralServiceImpl extends ServiceImpl<PlatformIntegralMapper, PlatformIntegral> implements IPlatformIntegralService {
    private final FzmChain fzmChain;
    private final IMerchantService merchantService;
    private final MsgProducer producer;
    private final DozerBeanMapper beanMapper;
    private final IUserService userService;
    private final IUserAssetService userAssetService;
    private final ISysConfigService configService;

    @Override
    public void initBaseIntegral(PlatformIntegral integral) {
        String platformMerchantId = MALLGlobalConfig.PLATFORM_MERCHANT_ID;
        Integer type = PlatformIntegralTypeEnum.BASE.getType();
        Integer status = PlatformIntegralStatusEnum.ABLE.getStatus();

        //是否已经初始化
        QueryWrapper<PlatformIntegral> qw = new QueryWrapper<>();
        qw.lambda().eq(PlatformIntegral::getType, type)
                .eq(PlatformIntegral::getStatus, status);
        if (getOne(qw) != null)
            return;

        //判断是否发行过
        if (fzmChain.coinExist(integral.getLabel())) {
            throw new MyException(MallResponseError.COIN_EXIST_ERROR);
        }

        //e3ac4b4a4e65460dbd9f1ec6cbd7a900_issue
        //e3ac4b4a4e65460dbd9f1ec6cbd7a900_recover

        String account = fzmChain.accountCreate(platformMerchantId + MALLGlobalConfig.ADDR_ISSUE_SUFFIX);
        String recoverAddr = fzmChain.accountCreate(platformMerchantId + MALLGlobalConfig.ADDR_RECOVER_SUFFIX);
        String priKey = fzmChain.addressPriKey(account);
        log.info(account);
        log.info(recoverAddr);
        log.info(priKey);

        integral.setAccount(account);
        integral.setRecoverAddr(recoverAddr);
        integral.setAddrKey(priKey);

        log.info("发行平台基础积分:"+integral.getAccount());

        //发行平台基础积分
        Map<String, String> map = fzmChain.IssueCoin(integral.getLabel(), integral.getIssueNum().intValue(),
                integral.getAccount());
        if (map.get("status").equals("SUCCESS")) {
            ClassPathResource resource = new ClassPathResource("template/ggb.jpg");
            InputStream inputStream = null;
            try {
                inputStream = resource.getInputStream();
            } catch (IOException e) {
                e.printStackTrace();
            }
            String logoPath = OSSUtil.uploadStream(inputStream, "manage/img/" + SerialIdsUtil.createDateStr() + "/", SerialIdsUtil.createFileName(".jpg"));

            SysConfig sysConfig = new SysConfig();
            sysConfig.setConfigId(UUIDUtil.getUUID());
            sysConfig.setDictKey("coin_logo");
            sysConfig.setDictValue(logoPath);
            sysConfig.setComm("支付积分logo");
            configService.save(sysConfig);

            save(integral);
        }
    }

    @Override
    public void setPlatFormIntegralPrice(SetIntegralPriceDTO dto) {
        Integer status = PlatformIntegralStatusEnum.ABLE.getStatus();

        QueryWrapper<PlatformIntegral> qw = new QueryWrapper<>();
        qw.lambda()
                .eq(PlatformIntegral::getLabel, dto.getLabel())
                .eq(PlatformIntegral::getStatus, status);
        PlatformIntegral platformIntegral = getOne(qw);

        platformIntegral.setPrice(dto.getPrice());
        updateById(platformIntegral);
    }

    @Override
    public void addPlatFormIntegral(AddIssueDTO dto) {
        Integer amount = dto.getAmount();
        String label = dto.getLabel();
        PlatformIntegral integral = queryByLabel(label);

        //发出增发请求，获得交易hash
        String hash = fzmChain.coinMintHash(label, integral.getAccount(), integral.getAddrKey(), amount);

        //轮询确认，异步执行
        Map<String, Object> map = new HashMap<>();
        map.put("hash", hash);
        map.put("amount", new BigDecimal(amount));
        map.put("label", label);

        //异步请求
        producer.sendTTL(map, QueueTTLTypeEnum.PLATFORM_INTEGRAL_ADD_TTL, 5 * 1000);
    }

    @Override
    public PlatformIntegral queryByLabel(String label) {
        Integer status = PlatformIntegralStatusEnum.ABLE.getStatus();
        QueryWrapper<PlatformIntegral> qw = new QueryWrapper<>();
        qw.lambda().eq(PlatformIntegral::getLabel, label)
                .eq(PlatformIntegral::getStatus, status);
        return getOne(qw);
    }

    @Override
    public void platFormTransSingle(TransferAccountsDTO dto) {
        //转账方信息
        PlatformIntegral integral = queryByLabel(MALLGlobalConfig.PLATFORM_BASE_INTEGRAL);
        String account = integral.getAccount();
        String addrKey = integral.getAddrKey();
        BigDecimal balanceNum = integral.getBalanceNum();

        //传参
        BigDecimal amount = dto.getAmount();
        String phone = dto.getPhone();
        Integer type = dto.getType();

        String oppositeAddr = "";
        String oppositeId = "";

        //余额不足判断
        if (balanceNum.compareTo(amount) == -1) {
            throw new MyException(MallResponseError.BALANCE_NOT_ENOUGH_ERROR);
        }

        //收账方信息
        if (type.equals(TranObjectEnum.MERCHANT.getType())) {
            Merchant merchant = merchantService.getByRegisterPhone(phone);
            if (merchant == null) {
                throw new MyException(MallResponseError.MERCHANT_NOT_EXIST);
            } else {
                oppositeAddr = merchant.getTokenIssueAddr();
                oppositeId = merchant.getMerchantId();
            }
        } else {
            User user = userService.queryByPhone(phone);
            if (user == null) {
                throw new MyException(MallResponseError.USER_NOT_EXIST_OR_LOCKING);
            } else {
                oppositeAddr = user.getAddress();
                oppositeId = user.getUid();
            }
        }

        //发出转账请求，获得交易hash
        String hash = fzmChain.tranTokenHash(account, addrKey, oppositeAddr, amount, MALLGlobalConfig.PLATFORM_BASE_INTEGRAL);

        //轮询确认，异步执行
        Map<String, Object> map = new HashMap<>();
        map.put("hash", hash);
        map.put("coin", MALLGlobalConfig.PLATFORM_BASE_INTEGRAL);
        map.put("amount", amount);
        map.put("oppositeAddr", oppositeAddr);
        map.put("oppositeId", oppositeId);
        map.put("type", type);

        //异步请求
        producer.sendTTL(map, QueueTTLTypeEnum.PLATFORM_INTEGRAL_TRAN_TTL, 5 * 1000);
    }

    @Override
    public void platFormTransBatch(PlatformTransBatchDTO dto) {
        //转账方信息
        PlatformIntegral integral = queryByLabel(MALLGlobalConfig.PLATFORM_BASE_INTEGRAL);

        List<Map<String, String>> maps = ExcelUtil.analysisExcel(dto.getPath());
        BigDecimal amountAll = BigDecimal.ZERO;

        for (Map<String, String> map : maps) {
            String phone = map.get("phone");
            //收账方信息
            if (dto.getType().equals(TranObjectEnum.MERCHANT.getType())) {
                Merchant merchant = merchantService.getByRegisterPhone(phone);
                if (merchant == null) {
                    throw new MyException(MallResponseError.MERCHANT_NOT_EXIST);
                }
            } else {
                User user = userService.queryByPhone(phone);
                if (user == null) {
                    throw new MyException(MallResponseError.USER_NOT_EXIST_OR_LOCKING);
                }
            }

            BigDecimal amount = new BigDecimal(map.get("amount"));
            amountAll = amountAll.add(amount);
        }

        //余额不足判断
        if (integral.getBalanceNum().compareTo(amountAll) == -1) {
            throw new MyException(MallResponseError.BALANCE_NOT_ENOUGH_ERROR);
        }

        for (Map<String, String> map : maps) {
            String phone = map.get("phone");
            BigDecimal amount = new BigDecimal(map.get("amount"));
            TransferAccountsDTO transDTO = new TransferAccountsDTO(phone, amount, dto.getType());
            platFormTransSingle(transDTO);
        }
    }

    @Override
    public void recoverPlatFormIntegral(RecoverDTO dto) {
        //传参
        String label = dto.getLabel();
        BigDecimal amount = dto.getAmount();

        //LSLA     http://119.45.170.21:8801
/*
                Balance(currency=0, balance=0.00000, frozen=0.00000, addr=113k4RfZeSUePdHmc3k1SMwwyYsjwdEeqB),
                Balance(currency=0, balance=0.00000, frozen=0.00000, addr=17e7QmGCbYKHpmdAg816SLEaP4bZoMf5KT),
                Balance(currency=0, balance=0.00000, frozen=0.00000, addr=14SKDPkp4AiZUXtmJum5pqV1PifjBqKPA3),
                Balance(currency=0, balance=0.00000, frozen=0.00000, addr=1LJ2xwWkbgsPJRSp15wLPvDfA4ntpkd1aP)*/

        //回收方信息
        PlatformIntegral integral = queryByLabel(label);
        String account = integral.getAccount();
        String addrKey = integral.getAddrKey();
        String recoverAddr = integral.getRecoverAddr();
        BigDecimal balanceNum = integral.getBalanceNum();

        //余额不足判断
        if (balanceNum.compareTo(amount) == -1) {
            throw new MyException(MallResponseError.BALANCE_NOT_ENOUGH_ERROR);
        }

        //发出转账请求，获得交易hash
        String hash = fzmChain.tranTokenHash(account, addrKey, recoverAddr, amount, label);

        //轮询确认，异步执行
        Map<String, Object> map = new HashMap<>();
        map.put("hash", hash);
        map.put("coin", label);
        map.put("amount", amount);

        //异步请求
        producer.sendTTL(map, QueueTTLTypeEnum.PLATFORM_INTEGRAL_RECOVER_TTL, 5 * 1000);
    }

    @Override
    public BaseIntegralDetailVO platformBaseIntegralDetail() {
        return beanMapper.map(queryByLabel(MALLGlobalConfig.PLATFORM_BASE_INTEGRAL), BaseIntegralDetailVO.class);
    }

    @Override
    public List<String> digitAssetsList() {
        Integer status = PlatformIntegralStatusEnum.ABLE.getStatus();
        QueryWrapper<PlatformIntegral> qw = new QueryWrapper<>();
        qw.lambda().ne(PlatformIntegral::getLabel, MALLGlobalConfig.PLATFORM_BASE_INTEGRAL)
                .eq(PlatformIntegral::getStatus, status);
        List<String> list = list(qw).stream().map(PlatformIntegral::getLabel)
                .collect(Collectors.toList());
        return list;
    }

    @Override
    public void recharge(UserAssetsChangeDTO dto) {
        //充值方信息
        PlatformIntegral integral = queryByLabel(MALLGlobalConfig.PLATFORM_BASE_INTEGRAL);
        String account = integral.getAccount();
        String addrKey = integral.getAddrKey();
        BigDecimal balanceNum = integral.getBalanceNum();

        //传参
        BigDecimal amount = dto.getAmount();
        String toAccount = dto.getAccount();
        String uid = dto.getUid();

        //余额不足判断
        if (balanceNum.compareTo(amount) == -1) {
            throw new MyException(MallResponseError.BALANCE_NOT_ENOUGH_ERROR);
        }

        //发出转账请求，获得交易hash
        String hash = fzmChain.tranTokenHash(account, addrKey, toAccount, amount, MALLGlobalConfig.PLATFORM_BASE_INTEGRAL);

        //轮询确认，异步执行
        Map<String, Object> map = new HashMap<>();
        map.put("hash", hash);
        map.put("coin", MALLGlobalConfig.PLATFORM_BASE_INTEGRAL);
        map.put("amount", amount);
        map.put("type", AssetsFlowTypeEnum.RECHARGE.getType());
        map.put("otherSide", toAccount);
        map.put("uid", uid);

        //异步请求
        producer.sendTTL(map, QueueTTLTypeEnum.USER_ASSETS_RECHARGE_OR_DEDUCTION_TTL, 5 * 1000);
    }

    @Override
    public void deduction(UserAssetsChangeDTO dto) {
        //传参
        String uid = dto.getUid();
        BigDecimal amount = dto.getAmount();
        String fromAccount = dto.getAccount();

        PlatformIntegral integral = queryByLabel(MALLGlobalConfig.PLATFORM_BASE_INTEGRAL);
        String account = integral.getAccount();

        //扣除方信息
        UserAsset userAsset = userAssetService.queryByUidAndCoin(uid, MALLGlobalConfig.PLATFORM_BASE_INTEGRAL);
        BigDecimal balanceNum = userAsset.getAmount();

        //余额不足判断
        if (balanceNum.compareTo(amount) == -1) {
            throw new MyException(MallResponseError.BALANCE_NOT_ENOUGH_ERROR);
        }

        //发出转账请求，获得交易hash
        String hash = fzmChain.tranTokenHash(fromAccount, null, account, amount, MALLGlobalConfig.PLATFORM_BASE_INTEGRAL);

        //轮询确认，异步执行
        Map<String, Object> map = new HashMap<>();
        map.put("hash", hash);
        map.put("coin", MALLGlobalConfig.PLATFORM_BASE_INTEGRAL);
        map.put("amount", amount);
        map.put("type", AssetsFlowTypeEnum.DEDUCTION.getType());
        map.put("otherSide", fromAccount);
        map.put("uid", uid);

        //异步请求
        producer.sendTTL(map, QueueTTLTypeEnum.USER_ASSETS_RECHARGE_OR_DEDUCTION_TTL, 5 * 1000);
    }

    @Override
    public PlatformIntegral queryByAddress(String address) {
        QueryWrapper<PlatformIntegral> qw = new QueryWrapper<>();
        qw.lambda().eq(PlatformIntegral::getAccount, address);
        return getOne(qw);
    }
}
