package com.fzm.mall.server.front.order.service.impl;

import cn.fzm.chain.simplesdk.client.MainChainClient;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fzm.mall.server.front.asset.model.OrderPay;
import com.fzm.mall.server.front.asset.model.UserAsset;
import com.fzm.mall.server.front.asset.model.UserAssetRecord;
import com.fzm.mall.server.front.asset.model.po.qo.OrderQO;
import com.fzm.mall.server.front.asset.service.IOrderPayService;
import com.fzm.mall.server.front.asset.service.IUserAssetRecordService;
import com.fzm.mall.server.front.asset.service.IUserAssetService;
import com.fzm.mall.server.front.base.PageVO;
import com.fzm.mall.server.front.base.ResponseVO;
import com.fzm.mall.server.front.constant.MallResponseEnum;
import com.fzm.mall.server.front.enums.CoinNameEnum;
import com.fzm.mall.server.front.enums.GoodsRedisEnum;
import com.fzm.mall.server.front.enums.QueueTTLTypeEnum;
import com.fzm.mall.server.front.enums.QueueTypeEnum;
import com.fzm.mall.server.front.goods.service.IGoodSkuPropService;
import com.fzm.mall.server.front.goods.service.ISkuService;
import com.fzm.mall.server.front.merchant.model.Merchant;
import com.fzm.mall.server.front.merchant.service.IMerchantService;
import com.fzm.mall.server.front.mq.MsgProducer;
import com.fzm.mall.server.front.order.model.*;
import com.fzm.mall.server.front.order.mapper.DeliveryMapper;
import com.fzm.mall.server.front.order.model.po.DeliveryPO;
import com.fzm.mall.server.front.order.model.po.TranDto;
import com.fzm.mall.server.front.order.model.vo.DeliveryVO;
import com.fzm.mall.server.front.order.service.IDeliveryService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fzm.mall.server.front.order.service.IPayRecordService;
import com.fzm.mall.server.front.order.service.IPayService;
import com.fzm.mall.server.front.repo.alipay.AlipayController;
import com.fzm.mall.server.front.repo.wxpay.NewWxpayController;
import com.fzm.mall.server.front.user.model.User;
import com.fzm.mall.server.front.user.service.IRedisService;
import com.fzm.mall.server.front.user.service.IUserService;
import com.fzm.mall.server.front.util.OrderUtil;
import com.sun.org.apache.xpath.internal.operations.Bool;
import io.netty.util.internal.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.math.BigDecimal;
import java.util.*;

/**
 * <p>
 * 用户提货表 服务实现类
 * </p>
 *
 * @author tdz
 * @since 2021-04-13
 */
@Service
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class DeliveryServiceImpl extends ServiceImpl<DeliveryMapper, Delivery> implements IDeliveryService {
    private final DeliveryMapper deliveryDao;
    private final IGoodSkuPropService skuPropService;
    private final IRedisService redisService;
    private final WuLiuService wuLiuService;
    private final IOrderPayService orderPayService;
    private final IMerchantService merchantService;
    private final IUserService userService;
    private final MainChainClient mainChainClient;
    private final IUserAssetRecordService userAssetRecordService;
    private final IUserAssetService userAssetService;
    private final MsgProducer producer;
    private final IPayService payService;
    private final IPayRecordService payRecordService;
    private final ISkuService skuService;

    @Autowired
    private MsgProducer msgProducer;
    @Autowired
    private IDeliveryService deliveryService;
    @Autowired
    private AlipayController alipayController;
    @Autowired
    private NewWxpayController newWxpayController;

    @Override
    public void handle(DeliveryVO deliveryVO) {
        String pid = deliveryVO.getPayId();
        String uid = deliveryVO.getUid();
        BigDecimal postFee = deliveryVO.getPostFee();
        Integer number = deliveryVO.getNumber();
        String deliveryId = deliveryVO.getDeliveryId();
        String merchantId = deliveryVO.getMerchantId();
        String coin = deliveryVO.getCoin();
        //减去用户冻结资产
        UserAsset assets = userAssetService.getAmountByUidAndCoinForUpdate(uid, coin);
        int i = userAssetService.deleteFrozen(assets.getId(), BigDecimal.valueOf(number));
        UserAssetRecord record = new UserAssetRecord();
        record.setUid(uid);
        record.setCoin(coin);
        record.setAmount(BigDecimal.valueOf(number));
        record.setType(18);//提货
        record.setStatus(2);//成功
        record.setFlowId(OrderUtil.getFlowId());
        record.setNote("提货");
        boolean saveReco = userAssetRecordService.save(record);
        if (saveReco) {
         log.error("资金记录保存失败");
        }
        Pay pay = payService.getByPidAndUid(pid, uid);
        pay.setState(1);
        pay.setPaidAmount(postFee);
        pay.setUnpaidAmount(BigDecimal.ZERO);
        pay.setPayTime(System.currentTimeMillis());
        payService.updateById(pay);
        //支付记录
        PayRecord payRecord = new PayRecord();
        payRecord.setPayId(pid);
        payRecord.setOid(deliveryId);
        payRecord.setPayTime(System.currentTimeMillis());
        payRecord.setPayType(pay.getPayType());
        payRecord.setMerchantId(merchantId);
        payRecord.setPayAmount(postFee);
        payRecord.setState(1);
        payRecordService.saveOrUpdate(payRecord);
        //生成提货单
        Delivery delivery = new Delivery();
        BeanUtils.copyProperties(deliveryVO, delivery);
        boolean save = save(delivery);
        if (save) {
            log.error("提货单保存失败");
        }
        return;
    }

    @Override
    public int payPostfeeByCoin(HashMap<String, Object> map) {
        DeliveryVO delivery = (DeliveryVO) map.get("delivery");
        Integer payType = delivery.getPayType();
        String uid = delivery.getUid();
        BigDecimal postFee = delivery.getPostFee();
        String merchantId = delivery.getMerchantId();
        String deliveryId = OrderUtil.getDeliveryId();
        delivery.setDeliveryId(deliveryId);

        //扣用户积分到商户
        int i = userAssetService.delAsset(uid, postFee, CoinNameEnum.MALLCOIN.value());

        UserAsset merchantCoin = userAssetService.getCoin(merchantId, CoinNameEnum.MALLCOIN.value());
        if (merchantCoin == null) {
            merchantCoin = new UserAsset();
            merchantCoin.setUid(merchantId);
            merchantCoin.setCoin(CoinNameEnum.MALLCOIN.value());
            merchantCoin.setType(0);//0支付币
            merchantCoin.setAmount(postFee);
        } else {
            merchantCoin.setAmount(merchantCoin.getAmount().add(postFee));
        }
        userAssetService.saveOrUpdate(merchantCoin);
        //扣并冻结用户资产
        int k = userAssetService.frozenUserAssets(uid, delivery.getCoin(), delivery.getNumber());
        if (k != 1) {
            throw new RuntimeException("资产不足");
        }
        if (i == 1) {
            OrderPay payResult = new OrderPay();
            payResult.setUid(uid);
            payResult.setOidsJson(JSON.toJSONString(deliveryId));
            payResult.setPayId(delivery.getPayId());
            payResult.setState(3);//3->支付中
            payResult.setPayTime(System.currentTimeMillis());
            payResult.setPayType(payType);
            payResult.setUnpaidAmount(postFee);
            payResult.setType(2);//2 支付邮费
            payResult.setTotal(postFee.compareTo(BigDecimal.ZERO) == 1 ? postFee : BigDecimal.valueOf(0));
            orderPayService.save(payResult);

            msgProducer.send(JSON.toJSONString(delivery), QueueTypeEnum.COIN_PAY_POSTFEE);
            return 1;
        } else {
            //资产不足
            return 0;
        }
    }

    /**
     * 支付成功处理提货单
     *
     * @param pid
     * @param outBizNo
     * @param type
     */
    @Transactional
    public void paymentsPostFee(String pid, String outBizNo, int type) {
        OrderPay payRes = orderPayService.getByPayId(pid);
        boolean b = false;
        if (payRes != null) {
            String uid = payRes.getUid();
            payRes.setPayType(type);
            payRes.setState(1);
            payRes.setOutBizNo(outBizNo);
            payRes.setPayTime(System.currentTimeMillis());
            //payResultService.updateById(payRes);
            String drawNo = payRes.getOidsJson();
            Delivery delivery = deliveryService.getByUidAndOrderDeliveryId(uid, JSON.parse(drawNo).toString());
            //log.error("payPostFee"+drawNo+drawGoods);
            if (delivery != null) {
                delivery.setDeliveryState(0);//待发货
                b = deliveryService.updateById(delivery);
                if (!b) {
                    throw new RuntimeException("提货修改商品为代发货失败");
                }
                int i = userAssetService.frozenUserAssets(uid, delivery.getCoin(), delivery.getNumber());
                if (i != 1) {
                    throw new RuntimeException("资产不足");
                }
            }
            BigDecimal num = BigDecimal.valueOf(delivery.getNumber());
            String coin = delivery.getCoin();
            b = orderPayService.updateById(payRes);
            if (!b) {
                throw new RuntimeException("修改提货订单结果失败");
            }
            //获取用户xls币地址
            String fromAddress = "";
            User user = userService.getByUid(uid);
            if (user != null) {
                fromAddress = user.getAddress();
            }
            //获取品牌方销毁地址
            String merchantId = delivery.getMerchantId();
            Merchant merchant = merchantService.info(merchantId);
            String toAddress = "";
            if (merchant != null) {
                toAddress = merchant.getTokenRecoverAddr();
            }
            String hash = mainChainClient.mainTranToken(fromAddress, null, toAddress, num, coin);
            UserAssetRecord record = new UserAssetRecord();
            record.setUid(uid);
            record.setCoin(coin);
            record.setAmount(num);
            record.setHash(hash);
            record.setType(18);//提货
            boolean saveReco = userAssetRecordService.save(record);
            if (!saveReco) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            }
            //货币打入商户回收地址
            TranDto tranDto = new TranDto();
            tranDto.setDelivery(null);
            tranDto.setId(record.getId());
            tranDto.setHash(hash);
            tranDto.setFromAddr(fromAddress);
            tranDto.setToAddr(toAddress);
            tranDto.setAmount(num);
            producer.sendTTL(JSON.toJSONString(tranDto), QueueTTLTypeEnum.CONFIRM_WITHDRAW_TTL,
                    5 * 1000);
        }
    }


    @Transactional
    @Override
    public JSONObject payDeliveryFee(HashMap<String, Object> map) {
        JSONObject object = new JSONObject();
        Delivery delivery = (Delivery) map.get("delivery");
        String ip = (String) map.get("ip");
        Integer num = (Integer) map.get("num");
        BigDecimal numBig = BigDecimal.valueOf(num);
        String coin = (String) map.get("coin");
        BigDecimal postFee = (BigDecimal) map.get("postFee");
        Integer payType = (Integer) map.get("payType");
        String orderDeliveryId = delivery.getOrderDeliveryId();
        String merchantId = delivery.getMerchantId();
        Merchant merchant = merchantService.info(merchantId);
        String uid = delivery.getUid();
        String toAddress = "";
        String fromAddress = "";
        User user = userService.getByUid(uid);
        if (user != null) {
            fromAddress = user.getAddress();
        }
        if (merchant != null) {
            toAddress = merchant.getTokenRecoverAddr();
        }
        if (!save(delivery)) {
            log.info("新增提货记录失败");
            throw new RuntimeException("提货单保存失败");
        }
        String form = "";
        if (postFee.compareTo(BigDecimal.ZERO) > 0) {
            OrderPay payResult = new OrderPay();
            payResult.setUid(uid);
            payResult.setOidsJson(JSON.toJSONString(orderDeliveryId));
            payResult.setPayId(OrderUtil.getPayId());
            payResult.setState(3);
            payResult.setPayTime(System.currentTimeMillis());
            payResult.setPayType(payType);
            payResult.setType(2);
            payResult.setTotal(postFee.compareTo(BigDecimal.ZERO) == 1 ? postFee : BigDecimal.valueOf(0));
            orderPayService.save(payResult);
            //支付宝支付
            if (payType.equals(1)) {
                JSONObject resObj = alipayController.payPostFee(payResult);
                if (!StringUtil.isNullOrEmpty(resObj.getString("result"))) {
                    object.put("result", "success");
                    object.put("pid", payResult.getPayId());
                } else {
                    object.put("form", resObj.getString("form"));
                    object.put("returnUrl", resObj.getString("returnUrl"));
                }
            }
            //微信支付
            if (payType.equals(2)) {
                form = newWxpayController.payPostFee(payResult, ip);
                if (form.equals("success")) {
                    object.put("result", "success");
                    object.put("pid", payResult.getPayId());
                } else {
                    object.put("mwebUrl", form);
                }
            }
        }
        if (postFee.compareTo(BigDecimal.ZERO) < 1) {
            int i = userAssetService.frozenUserAssets(uid, coin, num);
            if (i != 1) {
                //资产不足
                throw new RuntimeException("asset_not_enough");
            }
            if (delivery != null) {
                delivery.setDeliveryState(0);//待发货
                Boolean b = deliveryService.updateById(delivery);
                if (!b) {
                    throw new RuntimeException("提货修改商品为代发货失败");
                }
                i = userAssetService.frozenUserAssets(uid, delivery.getCoin(), delivery.getNumber());
                if (i != 1) {
                    throw new RuntimeException("资产不足");
                }
            }
            String hash = mainChainClient.mainTranToken(fromAddress, null, toAddress, numBig, coin);
            UserAssetRecord record = new UserAssetRecord();
            record.setAmount(numBig);
            record.setUid(uid);
            record.setCoin(coin);
            record.setType(18);//提货
            record.setHash(hash);
            record.setFlowId(OrderUtil.getFlowId());
            record.setAmount(postFee);
            record.setStatus(2);
            boolean saveReco = userAssetRecordService.save(record);
            if (!saveReco) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            }
            //货币打入商户回收地址
            TranDto tranDto = new TranDto();
            tranDto.setDelivery(null);
            tranDto.setId(record.getId());
            tranDto.setHash(hash);
            tranDto.setFromAddr(fromAddress);
            tranDto.setToAddr(toAddress);
            tranDto.setAmount(numBig);
            tranDto.setIsChain(false);
            producer.sendTTL(JSON.toJSONString(tranDto), QueueTTLTypeEnum.CONFIRM_WITHDRAW_TTL,
                    5 * 1000);
            object.put("pid", "");
            object.put("result", "success");
        }
        return object;
    }

    /**
     * 查询提货信息
     */
    @Override
    public DeliveryPO goodDelivery(final String oid) {
        DeliveryPO deliveryPO = new DeliveryPO();
        Delivery delivery = getOne(new QueryWrapper<Delivery>().eq("order_delivery_id", oid));
        BeanUtils.copyProperties(delivery, deliveryPO);
        return deliveryPO;
    }

    /**
     * 查询订单
     */
    @Override
    public DeliveryVO delivery(String oid) {
        DeliveryVO deliveryVO = deliveryDao.deliveryVO(oid);
        String skuId = deliveryVO.getSkuId();
        String merchantId = skuService.getSidBySkuId(skuId);
        //String expressDetail = getLogisticsByExpNo(deliveryVO.getDeliveryId(), deliveryVO.getExpressType(), deliveryVO.getExpressNo());
        List<Map<String, Object>> skuPropListMap = skuPropService.getSkuPropListBySkuId(skuId);
        deliveryVO.setPropList(skuPropListMap);
        deliveryVO.setMerchantId(merchantId);
        return deliveryVO;
    }

    /**
     * 分页查询订单
     */
    @Override
    public PageVO<DeliveryVO> pageDelivery(final OrderQO deliveryQO) {
        List<DeliveryVO> listOrder = deliveryDao.listDelivery(deliveryQO);
        for (DeliveryVO i : listOrder) {
            String skuId = i.getSkuId();
            List<Map<String, Object>> skuPropListMap = skuPropService.getSkuPropListBySkuId(skuId);
            i.setPropList(skuPropListMap);
        }
        Integer totalSize = deliveryDao.countDelivery(deliveryQO);
        PageVO<DeliveryVO> pageVO = new PageVO<>();
        pageVO.init(deliveryQO.getPage(), deliveryQO.getSize(), totalSize, listOrder);
        return pageVO;
    }

    /**
     * 分页查询售后订单
     */
    @Override
    public PageVO<DeliveryVO> pageAfterSaleDelivery(final OrderQO deliveryQO) {
        List<DeliveryVO> listOrder = deliveryDao.afterSaleDelivery(deliveryQO);
        for (DeliveryVO i : listOrder) {
            String skuId = i.getSkuId();
            List<Map<String, Object>> skuPropListMap = skuPropService.getSkuPropListBySkuId(skuId);
            i.setPropList(skuPropListMap);
        }
        Integer totalSize = deliveryDao.countAfterSaleDelivery(deliveryQO);
        PageVO<DeliveryVO> pageVO = new PageVO<>();
        pageVO.init(deliveryQO.getPage(), deliveryQO.getSize(), totalSize, listOrder);
        return pageVO;
    }

    @Override
    public void finish(String uid, String orderDeliveryId) {
        deliveryDao.finish(uid, orderDeliveryId, System.currentTimeMillis());
    }

    @Override
    public String queryLogistics(String orderDeliveryId) {
        String wuliu = redisService.getKey(GoodsRedisEnum.ORDER_DELIVERY_WULIU_KEY.value() + orderDeliveryId);
        if (StringUtil.isNullOrEmpty(wuliu)) {
            DeliveryPO deliveryPO = goodDelivery(orderDeliveryId);
            if (deliveryPO.getDeliveryState() == 2) {
                return "";
            }
            wuliu = wuLiuService.getWuliu(orderDeliveryId, deliveryPO.getExpressType(), deliveryPO.getExpressNo());
            redisService.setKey(GoodsRedisEnum.ORDER_DELIVERY_WULIU_KEY.value() + orderDeliveryId, wuliu, 1000 * 60 * 60 * 6);
        }
        return wuliu;
    }

    @Override
    public String getLogisticsByExpNo(String orderDeliveryId, String expressType, String expressNo) {
        String wuliu = redisService.getKey(GoodsRedisEnum.ORDER_DELIVERY_WULIU_KEY.value() + orderDeliveryId);
        if (StringUtil.isNullOrEmpty(wuliu)) {
            wuliu = wuLiuService.getWuliu(orderDeliveryId, expressType, expressNo);
            redisService.setKey(GoodsRedisEnum.ORDER_DELIVERY_WULIU_KEY.value() + orderDeliveryId, wuliu, 1000 * 60 * 60 * 6);
        }
        return wuliu;
    }

    @Override
    public int returnGoods(String uid, String orderDeliveryId) {
        return deliveryDao.returnGoods(uid, orderDeliveryId);
    }

    @Override
    public Integer getStatus(String orderDeliveryId) {
        return deliveryDao.getStatus(orderDeliveryId);
    }

    @Override
    public Delivery getByUidAndOrderDeliveryId(String uid, String orderDeliveryId) {
        QueryWrapper<Delivery> q = new QueryWrapper<>();
        q.eq("uid", uid);
        q.eq("order_delivery_id", orderDeliveryId);
        return getOne(q);
    }

    @Override
    public String getAddress(String orderDeliveryId) {
        return deliveryDao.getAddress(orderDeliveryId);
    }

    @Override
    public Integer getCountByUidAndOid(String uid, String orderId) {
        QueryWrapper<Delivery> q = new QueryWrapper<>();
        q.eq("order_delivery_id",orderId);
        q.eq("uid",uid);
        return count(q);
    }
}
