package com.qnfhq.modules.c2c.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.qnfhq.common.constant.Constant;
import com.qnfhq.common.page.PageData;
import com.qnfhq.common.redis.RedisUtils;
import com.qnfhq.common.service.impl.BaseServiceImpl;
import com.qnfhq.common.service.impl.CrudServiceImpl;
import com.qnfhq.common.utils.DateUtils;
import com.qnfhq.common.utils.MessageUtils;
import com.qnfhq.common.utils.Result;
import com.qnfhq.constant.CacheConstants;
import com.qnfhq.modules.c2c.dao.C2cOrderDao;
import com.qnfhq.modules.c2c.dto.C2cOrderCreateDTO;
import com.qnfhq.modules.c2c.dto.C2cOrderDTO;
import com.qnfhq.modules.c2c.dto.C2cOrderLogDTO;
import com.qnfhq.modules.c2c.entity.*;
import com.qnfhq.modules.c2c.enums.*;
import com.qnfhq.modules.c2c.service.*;
import cn.hutool.core.util.StrUtil;
import com.qnfhq.modules.user.entity.AppAssetEntity;
import com.qnfhq.modules.user.entity.AppUserEntity;
import com.qnfhq.modules.user.enums.AssetEnum;
import com.qnfhq.modules.user.enums.RecordEnum;
import com.qnfhq.modules.user.service.AppAssetService;
import com.qnfhq.modules.user.service.AppUserService;
import com.qnfhq.modules.user.service.AppWalletRecordService;
import com.qnfhq.utils.OrderUtils;
import com.qnfhq.utils.RandomNumberGenerator;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * c2c订单
 *
 * @author yelz 30262728@qq.com
 * @since 1.0.0 2025-11-17
 */
@Service
public class C2cOrderServiceImpl extends BaseServiceImpl<C2cOrderDao, C2cOrderEntity> implements C2cOrderService {
    @Resource
    private RedisUtils redisUtils;

    @Resource
    private AppUserService appUserService;

    @Resource
    private C2cOrderLogService c2cOrderLogService;

    @Resource
    private AppAssetService appAssetService;

    @Resource
    private AppAssetLogService appAssetLogService;

    @Resource
    private C2cAdService c2cAdService;

    @Resource
    private C2cAdLogService c2cAdLogService;

    @Resource
    private  C2cPaymentVoucherService c2cPaymentVoucherService;

    @Resource
    private  C2cOrderComplainService complainService;

    @Resource
    private AppWalletRecordService appWalletRecordService;

    @Resource
    private C2cOrderDao c2cOrderDao;


    @Override
    public PageData<C2cOrderEntity> page(Map<String, Object> params) {
        IPage<C2cOrderEntity> page = baseDao.selectPage(
                getPage(params, "id", false),
                getWrapper(params)
        );

        return getPageData(page, C2cOrderEntity.class);
    }


    public QueryWrapper<C2cOrderEntity> getWrapper(Map<String, Object> params){

        Integer direction = (Integer) params.get("direction");
        Integer flow = (Integer) params.get("flow");
        Integer status = (Integer) params.get("status");
        Integer isMt = (Integer) params.get("isMt");
        String orderNo = (String) params.get("orderNo");


        QueryWrapper<C2cOrderEntity> qw = new QueryWrapper<>();
        if(direction!=null && direction != -1) {
            qw.eq("direction", direction);
        }
        if(flow!=null && flow != -1) {
            qw.eq("flow",flow);
        }
        if(status!=null && status != -1) {
            qw.eq("status",status);
        }
        if(StrUtil.isNotEmpty(orderNo)) {
            qw.eq("order_no",orderNo);
        }
        if(isMt==null || isMt==1) {//用户
            qw.eq("user_id", StpUtil.getLoginIdAsLong());
        } else {
            //表示商家查询订单列表
            qw.eq("tran_user_id", StpUtil.getLoginIdAsLong());
        }

        return qw;
    }


//    @Override
//    public QueryWrapper<C2cOrderEntity> getWrapper(Map<String, Object> params){
//        String id = (String)params.get("id");
//
//        QueryWrapper<C2cOrderEntity> wrapper = new QueryWrapper<>();
//        wrapper.eq(StrUtil.isNotBlank(id), "id", id);
//
//        return wrapper;
//    }

    @Override
    public String getC2cOrderKeyByUid(String uid) {
        return new StringBuilder("c2c_order_uid:").append(uid).toString();
    }

    @Override
    public C2cOrderEntity getTradingByAdId(long adId) {
        return baseDao.selectOne(new LambdaQueryWrapper<C2cOrderEntity>()
                .eq(C2cOrderEntity::getC2cAdId, adId)
                .eq(C2cOrderEntity::getFlow, 0)
                .last(" limit 1")
        );
    }



    @Override
    public C2cOrderEntity selectOrder(Long id) {
        C2cOrderEntity order = selectOrderFromRedis(id);
        if(order == null) {
            order = selectById(id);
            if(order == null) {
                return null;
            }
            setOrderCache(order);
        }
        return order;
    }

    private String getC2cOrderKeyByOid(String oid) {
        return new StringBuilder("c2c_order_h:").append(oid).toString();
    }

    private C2cOrderEntity selectOrderFromRedis(Long id) {
        String odHKey = getC2cOrderKeyByOid(id.toString());
        log.error("odHKey:"+odHKey);
        Map<String, Object> odMap = redisUtils.hGetAll(odHKey);
        if(odMap == null || odMap.isEmpty()) {
            return null;
        }
        redisUtils.expire(odHKey, RandomNumberGenerator.getRandomNumber(3600,3*3600));

        C2cOrderEntity order = new C2cOrderEntity();
        order.setId(id);
        order.setOrderNo(Convert.toStr(odMap.get("orderNo")));
        order.setUserId(Convert.toLong(odMap.get("userId")));
        order.setUserName(Convert.toStr(odMap.get("userName")));
        order.setDirection(Convert.toInt(odMap.get("direction")));
        order.setLegalCoin(Convert.toStr(odMap.get("legalCoin")));
        order.setSymbol(Convert.toStr(odMap.get("symbol")));
        order.setC2cAdId(Convert.toLong(odMap.get("c2cAdId")));
        order.setTranUserId(Convert.toLong(odMap.get("tranUserId")));
        order.setTranUserName(Convert.toStr(odMap.get("tranUserName")));
        order.setTranPrice(Convert.toBigDecimal(odMap.get("tranPrice")));
        order.setSymbolNum(Convert.toBigDecimal(odMap.get("symbolNum")));
        order.setTranAmount(Convert.toBigDecimal(odMap.get("tranAmount")));
        order.setPayType(Convert.toInt(odMap.get("payType")));
        order.setFlow(Convert.toInt(odMap.get("flow")));
        order.setStatus(Convert.toInt(odMap.get("status")));
        order.setCreateTime(DateUtils.strForDate(Convert.toStr(odMap.get("createTime"))));
        order.setUpdateTime(DateUtils.strForDate(Convert.toStr(odMap.get("updateTime"))));
        order.setPayExpireTime(DateUtils.strForDate(Convert.toStr(odMap.get("payExpireTime"))));
        return order;
    }


    private void setOrderCache(C2cOrderEntity c2cOrder) {
        //设置订单 c2c_order_h:1
        String odHKey = getC2cOrderKeyByOid(c2cOrder.getId().toString());
        Map<String, Object> odMap = MapUtil.of("id", c2cOrder.getId());
        odMap.put("orderNo", c2cOrder.getOrderNo());
        odMap.put("userId", c2cOrder.getUserId());
        odMap.put("userName", c2cOrder.getUserName());
        odMap.put("direction", c2cOrder.getDirection());
        odMap.put("legalCoin", c2cOrder.getLegalCoin());
        odMap.put("symbol", c2cOrder.getSymbol());
        odMap.put("c2cAdId", c2cOrder.getC2cAdId());
        odMap.put("tranUserId", c2cOrder.getTranUserId());
        odMap.put("tranUserName", c2cOrder.getTranUserName());
        odMap.put("tranPrice", c2cOrder.getTranPrice());
        odMap.put("symbolNum", c2cOrder.getSymbolNum());
        odMap.put("tranAmount", c2cOrder.getTranAmount());
        odMap.put("payType", c2cOrder.getPayType());
        odMap.put("flow", c2cOrder.getFlow());
        odMap.put("status", c2cOrder.getStatus());
        odMap.put("createTime", DateUtils.format(c2cOrder.getCreateTime(),DateUtils.DATE_TIME_PATTERN));
        odMap.put("updateTime", DateUtils.format(c2cOrder.getUpdateTime(),DateUtils.DATE_TIME_PATTERN));
        odMap.put("payExpireTime", DateUtils.format(c2cOrder.getPayExpireTime(),DateUtils.DATE_TIME_PATTERN));
        redisUtils.hMSet(odHKey, odMap, RandomNumberGenerator.getRandomNumber(3600,3*3600));
    }
    private void setOrderUserIdCache(C2cOrderEntity c2cOrder) {
        //c2c_order_uid:1
        String odUserKey = getC2cOrderKeyByUid(c2cOrder.getUserId().toString());
        redisUtils.set(odUserKey, c2cOrder.getId().toString());
    }

    @Override
    public void deleteOrderCache(C2cOrderEntity c2cOrder) {
        String odHKey = getC2cOrderKeyByOid(c2cOrder.getId().toString());
        List list = new ArrayList<>();
        list.add(odHKey);
        String odUserKey = getC2cOrderKeyByUid(c2cOrder.getUserId().toString());
        list.add(odUserKey);
        redisUtils.delete(list);
    }

    @Override
    public void deleteOrderCache(String orderId,String userId) {
        String odHKey = getC2cOrderKeyByOid(orderId);
        List list = new ArrayList<>();
        list.add(odHKey);
        String odUserKey = getC2cOrderKeyByUid(userId);
        list.add(odUserKey);
        redisUtils.delete(list);
    }

    /**
     * 下订单，
     * 买入：创建订单，更新广告的可用数量
     * 卖出：创建订单，冻结卖家资产，更新广告的可用数量
     * @param c2cOrderDTO
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result createC2cOrder(C2cOrderCreateDTO c2cOrderDTO, C2cAdEntity c2cAd,BigDecimal legalCoinAmount, BigDecimal symbolNum,
                                 Long loginUserId, String realName) throws Exception {
        /** 1买入  2 卖出 */
        Integer direction = c2cOrderDTO.getDirection();
        /** 交易币 */
        String symbol = c2cOrderDTO.getSymbol().toLowerCase();
        /** 法定货币 */
        String legalCoin = c2cOrderDTO.getLegalCoin().toLowerCase();
        /** 广告编号 */
        Long c2cAdId = c2cOrderDTO.getC2cAdId();
        /** 支付方式 */
        Integer payType = c2cOrderDTO.getPayType();
        String adUserName = c2cAd.getUserName();
        BigDecimal price = c2cAd.getPrice();
        Long tranUserId = c2cAd.getUserId();

        C2cOrderEntity c2cOrder = new C2cOrderEntity();
        c2cOrder.setOrderNo("C"+ OrderUtils.generateAdNum());
        c2cOrder.setUserId(loginUserId);
        c2cOrder.setUserName(realName);
        c2cOrder.setDirection(direction);
        c2cOrder.setLegalCoin(legalCoin);
        c2cOrder.setSymbol(symbol);
        c2cOrder.setC2cAdId(c2cAdId);
        c2cOrder.setTranUserId(tranUserId);
        c2cOrder.setTranUserName(adUserName);
        c2cOrder.setTranPrice(price);
        c2cOrder.setSymbolNum(symbolNum);
        c2cOrder.setTranAmount(legalCoinAmount);
        c2cOrder.setPayType(payType);
        c2cOrder.setFlow(C2cOrderFlowEnum.PROGRESS.getCode());
        c2cOrder.setStatus(C2cOrderStatusEnum.CREATE.getCode());
        c2cOrder.setCreateTime(new Date());
        c2cOrder.setUpdateTime(new Date());

        String adHKey = CacheConstants.getC2cAdHKey(c2cAd.getId().toString());
        if(c2cOrderDao.insertC2cOrder(c2cOrder)<=0) {
            throw new Exception(MessageUtils.message("c2c.order.save.fail"));//保存广告失败
        }
        insertC2cOrderLog(c2cOrder.getId(), null, C2cOrderStatusEnum.CREATE.getCode(), "创建订单",loginUserId,"app");
        //用户卖出冻结资金
        if(c2cOrder.getDirection().intValue() == DirectionEnum.SELL.getCode().intValue()) {
            AppAssetEntity userPlatformAsset = appAssetService.getAppAssetEntity(c2cOrder.getUserId(),
                    c2cOrder.getSymbol(),AssetEnum.PLATFORM_ASSETS.getCode());
            if(userPlatformAsset.getAvailable().compareTo(c2cOrder.getSymbolNum())==-1) {
                throw new Exception(MessageUtils.message("c2c.order.availableAmount.insufficient"));//您的可用资产必须大于卖出数量
            }
            if (appAssetService.frozeAssetByUserId(loginUserId, c2cOrder.getSymbol(), c2cOrder.getSymbolNum()) == 0) {
                throw new Exception(MessageUtils.message("c2c.order.update.asset.fail"));//更新卖家资产失败
            }
            appAssetLogService.insertAssetLog(c2cOrder.getId(),c2cOrder.getUserId(),c2cOrder.getSymbol(),AssetEnum.PLATFORM_ASSETS.getCode(),
                    userPlatformAsset.getTotal(),userPlatformAsset.getTotal(),
                    userPlatformAsset.getAvailable(),userPlatformAsset.getAvailable().subtract(c2cOrder.getSymbolNum()),
                    userPlatformAsset.getFrozen(),userPlatformAsset.getFrozen().add(c2cOrder.getSymbolNum()),"c2c卖出冻结资产");
        }

        // 更新广告的可用数量
        BigDecimal newMaxAmount = null;
        Integer newStatus = null;
        BigDecimal maxAvail = c2cAd.getAvailableNum().subtract(symbolNum).multiply(price);
        if(c2cAd.getMaxAmount().compareTo(maxAvail)==1) {
            newMaxAmount = maxAvail;
        }
        if(maxAvail.compareTo(c2cAd.getMinAmount())==-1) {
            newStatus = AdStatusEnum.NOPASS.getCode();
            c2cAdService.deleteC2cAdCache(c2cAd);
        }
        if (c2cAdService.updateC2cAdAvailableNumById(c2cAdId, c2cOrder.getSymbolNum(), newMaxAmount, newStatus,c2cAd.getVersion()) == 0) {
            throw new Exception(MessageUtils.message("operation.fail.please.refresh"));//操作失败，请刷新后重试
        }
        c2cAdLogService.insertC2cAdLog(c2cAdId,c2cOrder.getId(),c2cOrder.getSymbolNum(),
                c2cAd.getAvailableNum(),c2cAd.getAvailableNum().subtract(c2cOrder.getSymbolNum()),
                c2cAd.getMaxAmount(),
                newMaxAmount!=null?newMaxAmount:c2cAd.getMaxAmount(),"创建C2C订单");


        //设置缓存
        setOrderCache(c2cOrder);
        setOrderUserIdCache(c2cOrder);

        if(c2cOrder.getDirection().intValue() == DirectionEnum.SELL.getCode().intValue()) {
            //如果是卖出，商家待支付数统计
            String unpayCountsKey = CacheConstants.getC2cMertUnPayKey(c2cOrder.getTranUserId().toString());
            redisUtils.increment(unpayCountsKey, 1L, RedisUtils.NOT_EXPIRE);
        }


        //发消息通知交易对手
//        HashMap<String, Object> object = new HashMap<>();
//        object.put("c2c_create",c2cOrder.getTranUserId().toString());
//        redisUtils.addStream(redisStreamNamesApi,object);

        return new Result().ok(c2cOrder.getId());

    }



    public void insertC2cOrderLog(Long id,Integer oldStatus,Integer newStatus,
                                  String remark,Long loginId,String opType) throws Exception {
        C2cOrderLogEntity c2cOrderLog = new C2cOrderLogEntity();
        c2cOrderLog.setId(id);
        c2cOrderLog.setOldStatus(oldStatus);
        c2cOrderLog.setNewStatus(newStatus);
        c2cOrderLog.setRemark(remark);
        c2cOrderLog.setOpUserId(loginId);
        c2cOrderLog.setOpType(opType);
        c2cOrderLog.setCreateTime(new Date());
        if(!c2cOrderLogService.insert(c2cOrderLog)) {
            throw new Exception(MessageUtils.message("c2c.order.log.fail"));//插入订单日志失败
        }
    }


    @Override
    public int cancelC2cOrderRedis(int oldStatus,C2cOrderEntity order) {
        //redis广告可用数量恢复
        C2cAdEntity c2cAd = c2cAdService.selectById(order.getC2cAdId());
        c2cAdService.deleteAdCache(c2cAd.getId(),c2cAd.getPayway().replaceAll("^,|,$", ""),c2cAd.getLegalCoin(),c2cAd.getSymbol(),c2cAd.getDirection());
        c2cAdService.setAdCache(c2cAd);
        deleteOrderCache(order);


        //待处理数量
        Long sellUserId = null;
        Long buyUserId = null;
        if(order.getDirection().intValue() == DirectionEnum.BUY.getCode().intValue()) {
            sellUserId = order.getTranUserId();
            if (oldStatus == C2cOrderStatusEnum.PAY.getCode().intValue()) {
                //商家待放币数-1
                String releaseCountsKey = CacheConstants.getC2cMertUnReleaseKey(sellUserId.toString());
                long count = redisUtils.decrement(releaseCountsKey, 1L, RedisUtils.NOT_EXPIRE);
                if(count < 0) {
                    redisUtils.delete(releaseCountsKey);
                }
            }

        } else {
            buyUserId = order.getTranUserId();
            if(oldStatus == C2cOrderStatusEnum.CREATE.getCode().intValue()) {
                //商家待支付数-1
                String unpayCountsKey = CacheConstants.getC2cMertUnPayKey(buyUserId.toString());
                long count = redisUtils.decrement(unpayCountsKey, 1L, RedisUtils.NOT_EXPIRE);
                if (count<0) {
                    redisUtils.delete(unpayCountsKey);
                }
            }
        }


        //发消息
//        HashMap<String, Object> object = new HashMap<>();
//        object.put("c2c_cancel",order.getTranUserId().toString());
//        redisUtil.addStream(redisStreamNamesApi,object);
        return 1;
    }


    /**
     * 买家主动取消
     * @param order
     * @return
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int cancelC2cOrder(C2cOrderEntity order,Long loginId) throws Exception {
        return cancelOrder(order,loginId,"app");
    }

    private int cancelOrder(C2cOrderEntity order,Long loginId,String source) throws Exception {
        //卖家
        Long sellUserId = getSellUserId(order);
        if(sellUserId==null) {
            throw new Exception(MessageUtils.message("c2c.seller.uid.not.empty"));//卖家编号不能空
        }

        insertC2cOrderLog(order.getId(), order.getStatus(), C2cOrderStatusEnum.CANCEL.getCode(),
                order.getRemark(),loginId,source);

        order.setFlow(C2cOrderFlowEnum.END.getCode());
        order.setStatus(C2cOrderStatusEnum.CANCEL.getCode());
        order.setUpdateTime(new Date());
        order.setCloseTime(new Date());
        if(!updateById(order)) {
            throw new Exception(MessageUtils.message("c2c.order.update.fail"));//更新订单失败
        }

        if(order.getDirection().intValue() == DirectionEnum.SELL.getCode().intValue()) {
            AppAssetEntity info = appAssetService.getAppAssetEntity(order.getUserId(),order.getSymbol(),AssetEnum.PLATFORM_ASSETS.getCode());
            if (appAssetService.unblockAssetByUserId(sellUserId, order.getSymbol(), order.getSymbolNum()) <= 0) {
                throw new Exception(MessageUtils.message("c2c.user.occupied.asset.fail"));//用户资产解冻失败
            }
            appAssetLogService.insertAssetLog(order.getId(),order.getUserId(),order.getSymbol(),AssetEnum.PLATFORM_ASSETS.getCode(),
                    info.getTotal(),info.getTotal(),
                    info.getAvailable(),info.getAvailable().add(order.getSymbolNum()),
                    info.getFrozen(),info.getFrozen().subtract(order.getSymbolNum()),"c2c订单取消解冻资产");
        }
        //广告可用数量恢复
        C2cAdEntity c2cAd = c2cAdService.selectById(order.getC2cAdId());
        BigDecimal maxAmount = null;
        if(order.getTranAmount().compareTo(c2cAd.getMaxAmount())==1) {
            maxAmount = order.getTranAmount();
        }
        if(c2cAdService.addC2cAdAvailableNumById(order.getC2cAdId(),order.getSymbolNum(),maxAmount,c2cAd.getVersion())<=0) {
            throw new Exception(MessageUtils.message("c2c.ad.availAmount.update.fail"));//更新广告可用数量失败
        }
        c2cAdLogService.insertC2cAdLog(order.getC2cAdId(),order.getId(),order.getSymbolNum(),
                c2cAd.getAvailableNum(),c2cAd.getAvailableNum().add(order.getSymbolNum()),
                c2cAd.getMaxAmount(),c2cAd.getMaxAmount(),"c2c订单取消,恢复广告可用数量");
        return 1;
    }

    /**
     * 客服取消订单
     * @param order
     * @param loginId
     * @return
     * @throws Exception
     */
    @Override
    public int kfCancelC2cOrder(C2cOrderEntity order,Long loginId) throws Exception {
        return cancelOrder(order,loginId,"web");
    }

    private Long getBuyUserId(C2cOrderEntity order) {
        if(order.getDirection().intValue() == DirectionEnum.BUY.getCode().intValue()) {
            return order.getUserId();
        } else {
            return order.getTranUserId();
        }
    }

    private Long getSellUserId(C2cOrderEntity order) {
        if(order.getDirection().intValue() == DirectionEnum.BUY.getCode().intValue()) {
            return order.getTranUserId();
        } else {
            return order.getUserId();
        }
    }

    /**
     * 买家确认付款
     * @param order
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result confirmPay(C2cOrderEntity order,Long loginId) throws Exception {
        Long buyUserId = getBuyUserId(order);
        Long sellUserId = getSellUserId(order);

        insertC2cOrderLog(order.getId(), order.getStatus(), C2cOrderStatusEnum.PAY.getCode(),
                order.getRemark(),loginId,"app");

        order.setStatus(C2cOrderStatusEnum.PAY.getCode());
        order.setPayTime(new Date());
        if(!updateById(order)) {
            throw new Exception(MessageUtils.message("c2c.order.update.fail"));//更新订单失败
        }
        //设置订单状态
        setOrderStatusCache(order);

        //用户买入，用户未支付数减1 或 商家放币订单数+1
        if(order.getDirection().intValue() == DirectionEnum.BUY.getCode().intValue()) {
            String releaseCountsKey = CacheConstants.getC2cMertUnReleaseKey(sellUserId.toString());
            redisUtils.increment(releaseCountsKey, 1L, RedisUtils.NOT_EXPIRE);
        } else {
            String unpayCountsKey = CacheConstants.getC2cMertUnPayKey(buyUserId.toString());
            long count = redisUtils.decrement(unpayCountsKey, 1L,RedisUtils.NOT_EXPIRE);
            if(count<0) {
                redisUtils.delete(unpayCountsKey);
            }
        }

        //发消息通知卖家
//        HashMap<String, Object> object = new HashMap<>();
//        object.put("c2c_pay",sellUserId.toString());
//        redisUtil.addStream(redisStreamNamesApi,object);
        return new Result();
    }


    /**
     * 更新缓存订单状态
     * @param order
     */
    private void setOrderStatusCache(C2cOrderEntity order) {
        String odHKey = getC2cOrderKeyByOid(order.getId().toString());
        if(redisUtils.hasKey(odHKey)) {
            redisUtils.hSet(odHKey, "status", order.getStatus());
        }
    }


    /**
     * 卖家发放
     * @param order
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int verifyReceipt(C2cOrderEntity order,Long loginId) throws Exception {
        Long buyUserId = getBuyUserId(order);
        Long sellUserId = getSellUserId(order);
        if(buyUserId==null || sellUserId==null || sellUserId.longValue() != loginId.longValue() ) {
            throw new Exception(MessageUtils.message("c2c.order.not.seller"));//您不是卖家
        }
        passCoin(order, sellUserId, buyUserId, loginId, "app");
        releaseCounts(order, sellUserId);
        return 1;
    }

    //商家未放币订单数-1
    private void releaseCounts(C2cOrderEntity order,Long sellUserId) {
        if(order.getDirection().intValue() == DirectionEnum.BUY.getCode().intValue()) {
            String releaseCountsKey = CacheConstants.getC2cMertUnReleaseKey(sellUserId.toString());
            long count = redisUtils.decrement(releaseCountsKey, 1L, RedisUtils.NOT_EXPIRE);
            if(count<0) {
                redisUtils.delete(releaseCountsKey);
            }
        }
    }

    /**
     * 客服放币
     * @param order
     * @return
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int kfPassCoin(C2cOrderEntity order,Long loginId) throws Exception {
        Long buyUserId = getBuyUserId(order);
        Long sellUserId = getSellUserId(order);
        return passCoin(order, sellUserId, buyUserId, loginId,"web");
    }

    private int passCoin(C2cOrderEntity order,Long sellUserId,Long buyUserId,Long loginId,String source) throws Exception{
        insertC2cOrderLog(order.getId(), order.getStatus(), C2cOrderStatusEnum.COMPLETE.getCode(),
                order.getRemark(),loginId,source);

        order.setFlow(C2cOrderFlowEnum.END.getCode());
        order.setStatus(C2cOrderStatusEnum.COMPLETE.getCode());
        order.setUpdateTime(new Date());
        order.setFinishTime(new Date());
        //1 更新订单状态已完成
        if(!updateById(order)) {
            throw new Exception(MessageUtils.message("c2c.order.update.fail"));//更新订单失败
        }
        //2 更新买家账户
        AppAssetEntity buyerAsset = appAssetService.getAppAssetEntity(buyUserId, order.getSymbol(), AssetEnum.PLATFORM_ASSETS.getCode());

        //判断是否需要创建买家资产账户
        if (Objects.isNull(buyerAsset)) {
            AppUserEntity buyUser = appUserService.selectById(buyUserId);
            appAssetService.createAsset(buyUser, order.getSymbol(), AssetEnum.PLATFORM_ASSETS.getCode());

            buyerAsset = new AppAssetEntity();
            buyerAsset.setTotal(BigDecimal.ZERO);
            buyerAsset.setFrozen(BigDecimal.ZERO);
            buyerAsset.setAvailable(BigDecimal.ZERO);
        }
        //卖家资产
        AppAssetEntity sellerAsset = appAssetService.getAppAssetEntity(sellUserId, order.getSymbol(), AssetEnum.PLATFORM_ASSETS.getCode());

        if (appAssetService.addAssetByUserId(buyUserId, order.getSymbol(), order.getSymbolNum()) <= 0) {
            throw new Exception(MessageUtils.message("c2c.buyer.asset.update.fail"));//更新买家资产失败
        }

        if(appAssetService.releaseAssetByUserId(sellUserId, order.getSymbol(), order.getSymbolNum()) <= 0) {
            throw new Exception(MessageUtils.message("c2c.seller.asset.update.fail"));//更新卖家资产失败
        }

        //买家资产变更记录
        appWalletRecordService.generateRecord(buyUserId, order.getSymbolNum(),
                RecordEnum.C2C_TRAN_BUY.getCode(), "system", order.getOrderNo(),
                RecordEnum.C2C_TRAN_BUY.getInfo(), buyerAsset.getTotal(), buyerAsset.getTotal().add(order.getSymbolNum()),
                order.getSymbol(), "");

        //卖家资产变更记录
        appWalletRecordService.generateRecord(sellUserId, order.getSymbolNum(),
                RecordEnum.C2C_TRAN_SELL.getCode(), "system", order.getOrderNo(),
                RecordEnum.C2C_TRAN_SELL.getInfo(), buyerAsset.getTotal(), buyerAsset.getTotal().subtract(order.getSymbolNum()),
                order.getSymbol(), "");

        deleteOrderCache(order);

        //通知买方已放币
//        HashMap<String, Object> object = new HashMap<>();
//        object.put("c2c_receipt", buyUserId.toString());
//        redisUtil.addStream(redisStreamNamesApi, object);
        return 1;
    }


    @Override
    public List<C2cOrderEntity> selectPaymentVoucherByOrderList(List<C2cOrderEntity> orderList) {
        if(!orderList.isEmpty()) {
            List<Long> orderIdList = new ArrayList<>();
            orderList.forEach(orderItem -> {
                if (orderItem.getStatus().intValue() != C2cOrderStatusEnum.CREATE.getCode()) {
                    orderIdList.add(orderItem.getId());
                }});
            if(!orderIdList.isEmpty()) {
                Long[] orderIds = new  Long[orderIdList.size()];
                orderIdList.toArray(orderIds);
                List<C2cPaymentVoucherEntity> paymentVoucherList = c2cPaymentVoucherService.selectC2cPaymentVoucherByIds(orderIds);
                Map<Long, List<C2cPaymentVoucherEntity>> payVouchGroup = paymentVoucherList.stream().collect(Collectors.groupingBy(C2cPaymentVoucherEntity::getOrderId));
                orderList.forEach(order -> {
                    if (payVouchGroup.containsKey(order.getId())) {
                        order.setIsVoucher(1);
                        order.setPayVoucherList(payVouchGroup.get(order.getId()));
                    } else {
                        order.setIsVoucher(0);
                    }
                });
            }
        }
        return orderList;
    }


    private List<Map> selectMtUnPayCount(Long tranUserId) {
        return c2cOrderDao.selectMtUnPayCount(tranUserId);
    }


    private List<Map> selectMtUnReleaseCount(Long tranUserId) {
        return c2cOrderDao.selectMtUnReleaseCount(tranUserId);
    }


    /**
     * 买家/卖家申诉
     * @param order
     * @return
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result complain(C2cOrderEntity order,C2cOrderComplainEntity c2cOrderComplain,Long loginId) throws Exception {
        Long buyUserId = getBuyUserId(order);
        Long sellUserId = getSellUserId(order);
        Result result = new Result();
        if(buyUserId.longValue()!=loginId.longValue() && sellUserId.longValue()!=loginId.longValue()) {
            return result.error(MessageUtils.message("c2c.order.not.buyer.seller"));//您不是交易用户，不能发起申诉
        }

        if(order.getStatus().intValue() == C2cOrderStatusEnum.COMPLAIN.getCode()) {
            return result;
        }

        insertC2cOrderLog(order.getId(), order.getStatus(), C2cOrderStatusEnum.COMPLAIN.getCode(), c2cOrderComplain.getReason(),StpUtil.getLoginIdAsLong(),"app");

        order.setStatus(C2cOrderStatusEnum.COMPLAIN.getCode());
        if(!updateById(order)) {
            throw new Exception(MessageUtils.message("c2c.order.pay.update.fail"));//订单更新失败
        }

        if(loginId.longValue() == order.getUserId().longValue()) {
            c2cOrderComplain.setFromUserId(order.getUserId());
            c2cOrderComplain.setFromUserName(order.getUserName());
            c2cOrderComplain.setToUserId(order.getTranUserId());
            c2cOrderComplain.setToUserName(order.getTranUserName());
        } else {
            c2cOrderComplain.setFromUserId(order.getTranUserId());
            c2cOrderComplain.setFromUserName(order.getTranUserName());
            c2cOrderComplain.setToUserId(order.getUserId());
            c2cOrderComplain.setToUserName(order.getUserName());
        }
        c2cOrderComplain.setStatus(C2cOrderComplainEnum.COMPLAINT.getCode());
        c2cOrderComplain.setCreateTime(new Date());
        if(!complainService.insert(c2cOrderComplain)) {
            throw new Exception(MessageUtils.message("c2c.order.complain.submit.fail"));//提交申诉失败
        }

        //设置订单状态
        setOrderStatusCache(order);

        //邮件通知被申诉人
//        TAppUser appUser = appUserService.getById(c2cOrderComplain.getToUserId());
//        if(StringUtils.isNotEmpty(appUser.getEmail())) {
//            String orderNo = new StringBuffer("******").append(StringUtils.substring(order.getOrderNo(),14)).toString();
//            String emailText = new StringBuffer("您的订单号").append(orderNo).append("，金额为").append(order.getSymbolNum()).append(order.getSymbol()).append("的C2C订单被提交申诉。请登录您的C2C订单详情页以处理申诉。").toString();
//            EmailUtils.sendComplainMail(appUser.getEmail(), emailText);
//        }

        releaseCounts(order, sellUserId);

        return result.ok(c2cOrderComplain.getId());
    }


    /**
     * 设置商家待支付订单数
     * @param unpayCountsKey
     * @return
     */
    @Override
    public Integer setMtUnPayCount(String unpayCountsKey) {
        List<Map> mtUpPayList = selectMtUnPayCount(StpUtil.getLoginIdAsLong());
        Map<String, Object> upPayMap = mtUpPayList.get(0);
        Integer unpayCounts = Convert.toInt(upPayMap.get("NUM"), 0);
        Random random = new Random();
        int randomSecond = random.nextInt(12*3600)+  12*3600; // 生成12到24之间的随机数
        redisUtils.set(unpayCountsKey, unpayCounts, randomSecond);
        return unpayCounts;
    }

    /**
     * 设置商家待放币数
     * @param releaseCountsKey
     * @return
     */
    @Override
    public Integer setMtUnReleaseCount(String releaseCountsKey) {
        List<Map> mtReleaseList = selectMtUnReleaseCount(StpUtil.getLoginIdAsLong());
        Map<String,Object> releaseMap = mtReleaseList.get(0);
        Integer releaseCounts = Convert.toInt(releaseMap.get("NUM"),0);
        Random random = new Random();
        int randomSecond = random.nextInt(12*3600)+12*3600; // 生成12到24之间的随机数
        redisUtils.set(releaseCountsKey,releaseCounts,randomSecond);
        return releaseCounts;
    }

    /**
     * 检查登陆用户是否是买家或卖家
     * @param order
     * @return true 是
     */
    @Override
    public boolean checkOrderTranUser(C2cOrderEntity order)
    {
        if(order.getUserId().longValue()==StpUtil.getLoginIdAsLong() ||
                order.getTranUserId().longValue()==StpUtil.getLoginIdAsLong() ) {
            return true;
        } else {
            return false;
        }
    }

}