package com.diaoyun.zion.chinafrica.service.impl;

import com.diaoyun.zion.chinafrica.bis.impl.StripePay;
import com.diaoyun.zion.chinafrica.constant.KeyConstant;
import com.diaoyun.zion.chinafrica.dao.*;
import com.diaoyun.zion.chinafrica.entity.*;
import com.diaoyun.zion.chinafrica.enums.DeliveryStatusEnum;
import com.diaoyun.zion.chinafrica.enums.OrderStatusEnum;
import com.diaoyun.zion.chinafrica.service.*;
import com.diaoyun.zion.chinafrica.vo.*;
import com.diaoyun.zion.master.base.Result;
import com.diaoyun.zion.master.base.StateConstant;
import com.diaoyun.zion.master.common.RedisCache;
import com.diaoyun.zion.master.common.TokenManager;
import com.diaoyun.zion.master.config.DomainProperties;
import com.diaoyun.zion.master.enums.ResultCodeEnum;
import com.diaoyun.zion.master.security.JwtTokenProvider;
import com.diaoyun.zion.master.util.AESUtils;
import com.diaoyun.zion.master.util.GsonUtil;
import com.diaoyun.zion.master.util.HttpClientUtil;
import com.diaoyun.zion.master.util.IdUtil;
import com.diaoyun.zion.master.validator.Validator;
import com.github.pagehelper.PageInfo;
import com.stripe.exception.StripeException;
import com.stripe.model.Charge;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;

import static com.github.pagehelper.page.PageMethod.startPage;

/**
 * Service实现类
 *
 * @author G
 * @date 2019-08-14 09:11:48
 */
@Service("tbCfOrderService")
public class TbCfOrderServiceImpl implements TbCfOrderService {
    private static Logger logger = LoggerFactory.getLogger(TbCfOrderServiceImpl.class);

    @Autowired
    private TbCfOrderDao tbCfOrderDao;
    @Autowired
    private TbCfCouponDao tbCfCouponDao;
    @Autowired
    private TbCfAddressDao tbCfAddressDao;
    @Autowired
    private TbCfItemOrderRDao tbCfItemOrderRDao;
    @Autowired
    private TbCfItemDetailDao tbCfItemDetailDao;
    @Autowired
    private TbCfCartRecordRDao tbCfCartRecordRDao;
    @Autowired
    private TbCfIssueCouponDao tbCfIssueCouponDao;
    @Autowired
    private TbCfTakeCouponDao tbCfTakeCouponDao;
    @Autowired
    private TbCfTaxDao tbCfTaxDao;
    @Autowired
    private TbCfCouponUseDao tbCfCouponUseDao;
    @Autowired
    private TbCfFinanceDao tbCfFinanceDao;
    @Autowired
    private TbCfToiCouponDao tbCfToiCouponDao;
    @Autowired
    private TbCfExpressTemplateDao tbCfExpressTemplateDao;
    @Autowired
    private JwtTokenProvider jwtTokenProvider;

    @Autowired
    private TbCfFeeService tbCfFeeService;
    @Autowired
    private TbCfCouponService tbCfCouponService;

    @Autowired
    private SpiderService spiderService;


    @Resource
    private RedisCache<Object> orderRedisCache;

    @Autowired
    private DomainProperties domainProperties;

    @Autowired
    @Qualifier("redisTokenManager")
    private TokenManager tokenManager;

    @Autowired
    private HttpServletRequest request; //自动注入request

    @Autowired
    private TbCfIssueCouponService tbCfIssueCouponService; //发放表


    @Override
    public TbCfOrderEntity queryObject(String orderId) {
        return tbCfOrderDao.queryObject(orderId);
    }

    @Override
    public List<TbCfOrderEntity> queryList(Map<String, Object> map) {
        return tbCfOrderDao.queryList(map);
    }

    @Override
    public int queryTotal(Map<String, Object> map) {
        return tbCfOrderDao.queryTotal(map);
    }

    @Override
    public int save(TbCfOrderEntity tbCfOrder) {
        tbCfOrder.setOrderId(IdUtil.createIdbyUUID());
        return tbCfOrderDao.save(tbCfOrder);
    }

    @Override
    public int update(TbCfOrderEntity tbCfOrder) {
        return tbCfOrderDao.update(tbCfOrder);
    }

    @Override
    public int delete(String orderId) {
        return tbCfOrderDao.delete(orderId);
    }

    @Override
    public int deleteBatch(String[] orderIds) {
        return tbCfOrderDao.deleteBatch(orderIds);
    }

    /**
     * 用户计算1
     *
     * @return
     * @throws IOException
     * @throws URISyntaxException
     * @throws ExecutionException
     * @throws InterruptedException
     * @throws TimeoutException
     */
    @Override
    public Result settleAccount(String toitableId) throws IOException, URISyntaxException, ExecutionException, InterruptedException, TimeoutException {
        Result<TbCfOrderVo> result = new Result<>();
        //获取用户
        String token = jwtTokenProvider.resolveToken(request);
        TbCfUserInfoVo tbCfUserInfoVo = tokenManager.validate(token);
        //获取购物车已勾选 商品
        List<TbCfCartItemDetailVo> tbCfCartItemDetailList = tbCfItemDetailDao.getCartItemList(tbCfUserInfoVo.getUserId(), StateConstant.VALID);
        if (tbCfCartItemDetailList.isEmpty()) {
            result.setCode(ResultCodeEnum.VALIDATE_ERROR.getCode()).setMessage("There are no items in the shopping cart");
        } else {
            //获取订单数据
            TbCfOrderVo tbCfOrder = getOrderData(tbCfUserInfoVo, tbCfCartItemDetailList, toitableId);
            result.setData(tbCfOrder).setMessage("Order pending settlement");
        }
        return result;
    }

    @Override
    public Result placeOrder(TbCfOrderVo pageOrder, String toitableId) throws IOException, URISyntaxException, ExecutionException, InterruptedException, TimeoutException {
        System.out.println(toitableId + "发放ID");
        Result<TbCfOrderVo> result = new Result<>();
        //获取用户
        String token = jwtTokenProvider.resolveToken(request);
        TbCfUserInfoVo tbCfUserInfoVo = tokenManager.validate(token);
        //获取购物车已勾选 商品
        List<TbCfCartItemDetailVo> tbCfCartItemDetailList = tbCfItemDetailDao.getCartItemList(tbCfUserInfoVo.getUserId(), StateConstant.VALID);

        if (tbCfCartItemDetailList.isEmpty()) {
            result.setCode(ResultCodeEnum.VALIDATE_ERROR.getCode()).setMessage("There are no items in the shopping cart");
        } else {
            //获取下单的订单数据
            TbCfOrderVo definiteOrder = ensureOrder(tbCfUserInfoVo, pageOrder, tbCfCartItemDetailList, toitableId);
            for( TbCfCartItemDetailVo itemList: tbCfCartItemDetailList ){
                TbCfItemOrderREntity  tbCfItemOrderREntity=new TbCfItemOrderREntity();
                tbCfItemOrderREntity.setOrderItemId(IdUtil.createIdbyUUID());
                tbCfItemOrderREntity.setOrderId(definiteOrder.getOrderId());
                tbCfItemOrderREntity.setItemId(itemList.getItemId());
                tbCfItemOrderREntity.setEnableFlag(StateConstant.VALID);
                tbCfItemOrderREntity.setDeliveryFlag(DeliveryStatusEnum.PROCESSING.getValue());
                tbCfItemOrderREntity.setOrderStatus(OrderStatusEnum.PENDING_PAY.getValue());
                tbCfItemOrderREntity.setUpdateTime(new Date());
                tbCfItemOrderRDao.save(tbCfItemOrderREntity);
            }
            //持久化订单数据
            TbCfOrderEntity tbCfOrderEntity = new TbCfOrderEntity();
            BeanUtils.copyProperties(definiteOrder, tbCfOrderEntity);

            tbCfOrderDao.save(tbCfOrderEntity);
            //成功下单后的处理 清空购物车 将商品加入订单中 使用优惠券
            afterPlaceOrder(tbCfOrderEntity.getOrderId(), tbCfCartItemDetailList, definiteOrder);
            result.setData(definiteOrder).setMessage(ResultCodeEnum.SUCCESS.getDesc());
        }
        return result;
    }


    @Override
    public Result getUserOrderList(Integer pageNum, Integer pageSize, Integer orderStatus) throws InterruptedException {
        Result<PageInfo<TbCfOrderVo>> result = new Result<>();
        //获取用户
        synchronized (this) {
            String token = jwtTokenProvider.resolveToken(request);
            TbCfUserInfoVo tbCfUserInfoVo = tokenManager.validate(token);
            //订单数据
            List<TbCfOrderEntity> orderList = tbCfOrderDao.getUserOrderList(tbCfUserInfoVo.getUserId(), orderStatus);
            startPage(pageNum, pageSize);
            PageInfo<TbCfOrderEntity> pageInfo = new PageInfo<>(orderList);
            //获取订单后，再获取订单内商品
            List<TbCfOrderEntity> pagingOrderList = pageInfo.getList();
            List<TbCfOrderVo> tbCfOrderVoList = new ArrayList<>();
            if (!pagingOrderList.isEmpty()) {
                for (TbCfOrderEntity order : pagingOrderList) {
                    TbCfOrderVo orderVo = new TbCfOrderVo();
                    BeanUtils.copyProperties(order, orderVo);
                    //获取订单内商品
                    List<TbCfItemDetailEntity> tbCfItemDetailList = tbCfOrderDao.getOrderItemList(orderVo.getOrderId());
                    //返回的订单商品详情
                    List<TbCfCartItemDetailVo> itemDetailVoList = new ArrayList<>();
                    for (TbCfItemDetailEntity tbCfItemDetail : tbCfItemDetailList) {
                        TbCfCartItemDetailVo tbCfCartItemDetailVo = new TbCfCartItemDetailVo();
                        BeanUtils.copyProperties(tbCfItemDetail, tbCfCartItemDetailVo);
                        tbCfCartItemDetailVo.setOrdersId(tbCfOrderDao.getOrdersId(orderVo.getOrderId(), tbCfItemDetail.getItemId()));
                        itemDetailVoList.add(tbCfCartItemDetailVo);
                    }
                    orderVo.setItemDetailList(itemDetailVoList);
                    tbCfOrderVoList.add(orderVo);
                }
            }
            PageInfo<TbCfOrderVo> returnPageInfo = new PageInfo<>();
            BeanUtils.copyProperties(pageInfo, returnPageInfo);
            returnPageInfo.setList(tbCfOrderVoList);
            result.setData(returnPageInfo);
        }
        return result;
    }


    @Override
    public void cancelOrder(String orderId, String userId, String couponId) {
        //更改订单状态
        TbCfItemOrderREntity tbCfItemOrderREntity = new TbCfItemOrderREntity();
        tbCfItemOrderREntity.setOrderId(orderId);
        tbCfItemOrderREntity.setOrderStatus(OrderStatusEnum.CLOSE.getValue());
        tbCfItemOrderREntity.setUpdateTime(new Date());
        tbCfItemOrderREntity.setCloseTime(new Date());
        tbCfItemOrderRDao.update(tbCfItemOrderREntity);
        //优惠券不为空，则设置状态
        if (StringUtils.isNotBlank(userId) && StringUtils.isNotBlank(couponId)) {
            //更新领取记录已领取
            tbCfToiCouponDao.updateEnableFlag(userId, couponId, StateConstant.VALID);//int res =
        }
    }

    @Override
    public Result getStripePublicKey() {
        String pk = domainProperties.getProperty("stripe.pk");
        return new Result().setData(pk);
    }

    @Override
    public Result payForOrder(String orderId, String token) {
        Result<TbCfFinanceVo> result = new Result<>();
        TbCfOrderVo tbCfOrderVo = (TbCfOrderVo) orderRedisCache.get(KeyConstant.ORDER_DET + orderId);
        if (tbCfOrderVo != null) {
            BigDecimal realityPay = tbCfOrderVo.getRealityPay();
            BigDecimal magnification = new BigDecimal("100");
            String stripeSk = AESUtils.decrypt(KeyConstant.AES_KEY, domainProperties.getProperty("stripe.sk"));
            try {
                Charge charge = StripePay.createCharge(realityPay.multiply(magnification).intValue(), stripeSk, token);
                //The status of the payment is either succeeded, pending, or failed
                if ("succeeded".equals(charge.getStatus())) {
                    result.setMessage(ResultCodeEnum.SUCCESS.getDesc());
                    //支付成功后的处理
                    //从缓存删除
                    removeRedisCache(tbCfOrderVo);
                    //更改订单状态
                    changeOrderState(charge.getId(), tbCfOrderVo);
                    //修改使用的优惠券的状态
                    if (tbCfOrderVo.getCouponId() != null && "20".equals(tbCfOrderVo.getOrderStatus())) {
                        tbCfToiCouponDao.changeCoupnStatus(tbCfOrderVo.getUserId(), tbCfOrderVo.getCouponId());
                    }
                    //生成流水记录
                    TbCfFinanceEntity tbCfFinance = createFinance(charge, tbCfOrderVo);
                    TbCfFinanceVo tbCfFinanceVo = new TbCfFinanceVo();
                    BeanUtils.copyProperties(tbCfFinance, tbCfFinanceVo);
                   /*//赠送购物返券
                    List<TbCfCouponEntity> couponList = tbCfCouponDao.getCouponByCategory(CouponCategoryEnum.SHOP.getValue(), new Date());
                    if (!couponList.isEmpty()) {
                        //领取优惠券
                        Result couponResult = tbCfCouponService.takeCoupon(couponList.get(0).getCouponId());
                        if (couponResult.getCode() == ResultCodeEnum.SUCCESS.getCode()) {
                            tbCfFinanceVo.setCouponId(couponList.get(0).getCouponId());
                        }
                    }*/
                    result.setData(tbCfFinanceVo);
                } else {
                    result.setCode(ResultCodeEnum.SERVICE_ERROR.getCode()).setMessage("Payment failed!");
                }
                return result;
            } catch (StripeException e) {
                result.setCode(ResultCodeEnum.SERVICE_ERROR.getCode()).setMessage(e.getMessage());
                logger.error(e.getMessage(), e);
                return result;
            }
            //The status of the payment is either succeeded, pending, or failed
        } else {
            result.setCode(ResultCodeEnum.VALIDATE_ERROR.getCode()).setMessage("Order does not exist!");
        }
        return result;
    }

    /**
     * 查询物流信息
     *
     * @param orderId
     * @return
     * @throws IOException
     */
    @Override
    public Result queryOrderExpressInfo(String orderId) throws IOException {
        String expressUrl = domainProperties.getProperty("express.info.api");
        String userNo = domainProperties.getProperty("express.info.user_no");
        String token = domainProperties.getProperty("express.info.token");
        Map<String, Object> paramMap = new HashMap<>();
        List<Map<String, String>> data = new ArrayList<>();
        Map<String, String> dataMap = new HashMap<>();
        dataMap.put("order_no", orderId);
        data.add(dataMap);
        paramMap.put("user_no", userNo);
        paramMap.put("token", token);
        paramMap.put("data", data);
        String resultStr = HttpClientUtil.sendPostWithBodyParameter(expressUrl, paramMap);
        Map resultMap = GsonUtil.GsonToMaps(resultStr);
        return new Result<>(resultMap);
    }

    /**
     * 获取某段时间的付款订单数据
     * @return
     */
    @Override
    public Result getOrderListByTime(long beginTime, long endTime, Integer pageNum, Integer pageSize) {
        Result result = new Result<>();
        if ((endTime - beginTime) > 31 * 24 * 60 * 60) {
            result.setCode(ResultCodeEnum.ERROR.getCode()).setMessage("Time interval is too long");
        } else {
            startPage(pageNum, pageSize);
            Date beginDate = new Date(beginTime * 1000);
            Date endDate = new Date(endTime * 1000);
            List<TbCfOrderEntity> orderList = tbCfOrderDao.getOrderListByTime(beginDate, endDate);
            PageInfo<TbCfOrderEntity> pageInfo = new PageInfo<>(orderList);
            result.setData(pageInfo);
        }
        return result;
    }
    /**
     * 获取某段时间已发货订单数据
     * @return
     */
    @Override
    public Result getDeliveryList(long beginTime, long endTime, Integer pageNum, Integer pageSize) {
        Result result = new Result<>();
        if ((endTime - beginTime) > 31 * 24 * 60 * 60) {
            result.setCode(ResultCodeEnum.ERROR.getCode()).setMessage("Time interval is too long");
        } else {
            startPage(pageNum, pageSize);
            Date beginDate = new Date(beginTime * 1000);
            Date endDate = new Date(endTime * 1000);
            List<TbCfItemShippedEntity> orderList = tbCfOrderDao.getDeliveryList(beginDate, endDate);
            // TODO 暂设为赞比亚
            for(TbCfItemShippedEntity list:orderList ){
                list.setCountry("赞比亚");
            }
            PageInfo<TbCfItemShippedEntity> pageInfo = new PageInfo<>(orderList);
            result.setData(pageInfo);
        }
        return result;
    }
    /**
     * 根据订单号获取详细订单数据 给第三方的接口
     * @param orderId
     * @return
     */
    @Override
    public Result getOrderDetailThird(String orderId) {
        Result<OrderEntity> result = new Result<>();
        OrderEntity order = tbCfOrderDao.getOrder(orderId);
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setOrderId(order.getOrderId());
        orderEntity.setDeliveryPhone(order.getDeliveryPhone());
        orderEntity.setDeliveryName(order.getDeliveryName());
        orderEntity.setDeliveryAddress(order.getDeliveryAddress());
        orderEntity.setOrderNo(order.getOrderNo());
        orderEntity.setUserName(order.getUserName());
        //获取订单内商品
        List<ItemEntity> items = tbCfOrderDao.getItemList(orderId);
        //返回的订单商品详情
        List<ItemEntity> itemList = new ArrayList<>();
        for (ItemEntity item : items) {
            ItemEntity entity = new ItemEntity();
            entity.setItemNum(item.getItemNum());
            entity.setItemCategory(item.getItemCategory());
            entity.setItemPrice(item.getItemPrice());
            entity.setItemTitle(item.getItemTitle());
            entity.setItemId(item.getItemId());
            entity.setDescripitionName(item.getDescripitionName());
            itemList.add(entity);
        }
        orderEntity.setItemDetailList(itemList);
        result.setData(orderEntity);
        return result;
    }
    @Override
    public Result deleteOrder(String orderId) {
        Result result = new Result();
        TbCfOrderEntity tbCfOrder = new TbCfOrderEntity();
        tbCfOrder.setOrderId(orderId);
        tbCfOrder.setUpdateTime(new Date());
        tbCfOrder.setEnableFlag(StateConstant.INVALID);
        int res = tbCfOrderDao.update(tbCfOrder);
        if (res > 0) {
            result.setMessage(ResultCodeEnum.SUCCESS.getDesc());
        } else {
            result.setCode(ResultCodeEnum.DAO_ERROR.getCode()).setMessage(ResultCodeEnum.DAO_ERROR.getDesc());
        }
        return result;
    }

    @Override
    public Result getOrderDetail(String orderId) {
        Result<TbCfOrderVo> result = new Result<>();
        TbCfOrderEntity tbCfOrderEntity = tbCfOrderDao.queryObject(orderId);
        TbCfOrderVo tbCfOrderVo = new TbCfOrderVo();
        BeanUtils.copyProperties(tbCfOrderEntity, tbCfOrderVo);
        //获取订单内商品
        List<TbCfItemDetailEntity> tbCfItemDetailList = tbCfOrderDao.getOrderItemList(orderId);
        //返回的订单商品详情
        List<TbCfCartItemDetailVo> itemDetailVoList = new ArrayList<>();
        for (TbCfItemDetailEntity tbCfItemDetail : tbCfItemDetailList) {
            TbCfCartItemDetailVo tbCfCartItemDetailVo = new TbCfCartItemDetailVo();
            BeanUtils.copyProperties(tbCfItemDetail, tbCfCartItemDetailVo);
            tbCfCartItemDetailVo.setOrdersId(tbCfOrderDao.getOrdersId(orderId, tbCfItemDetail.getItemId()));
            itemDetailVoList.add(tbCfCartItemDetailVo);
        }
        tbCfOrderVo.setItemDetailList(itemDetailVoList);
        result.setData(tbCfOrderVo);
        return result;
    }

    @Override
    public Result getDescriptionById(String descriptionId) {
        Result<ExpressTemplateVo> result = new Result<>();
        ExpressTemplateVo tbCfExpressTemplateEntity= new ExpressTemplateVo();
        ExpressTemplateVo expressTemplate=tbCfExpressTemplateDao.getDescriptionById(descriptionId);
        tbCfExpressTemplateEntity.setDescriptionId(expressTemplate.getDescriptionId());
        tbCfExpressTemplateEntity.setDescriptionName(expressTemplate.getDescriptionName());
        tbCfExpressTemplateEntity.setExpressFee(expressTemplate.getExpressFee());
        tbCfExpressTemplateEntity.setCountryCode(expressTemplate.getCountryCode());
        tbCfExpressTemplateEntity.setCreateTime(expressTemplate.getCreateTime());
        result.setData(tbCfExpressTemplateEntity);
        return result;
    }


    /**
     * 记录财务流水
     *
     * @param charge
     * @param tbCfOrderVo
     */
    private TbCfFinanceEntity createFinance(Charge charge, TbCfOrderVo tbCfOrderVo) {
        TbCfFinanceEntity tbCfFinance = new TbCfFinanceEntity();
        tbCfFinance.setOrderId(tbCfOrderVo.getOrderId());
        tbCfFinance.setFinaceId(IdUtil.createIdbyUUID());
        tbCfFinance.setPayAccount(tbCfOrderVo.getRealityPay());
        tbCfFinance.setPayId(charge.getId());
        tbCfFinance.setPayTime(new Date());
        tbCfFinance.setReceiptUrl(charge.getReceiptUrl());
        //暂时用 stripe
        tbCfFinance.setPayWayCode("stripe");
        tbCfFinance.setUserId(tbCfOrderVo.getUserId());
        tbCfFinanceDao.save(tbCfFinance);
        return tbCfFinance;
    }

    /**
     * 更改订单状态
     *
     * @param payId
     * @param oldOrder
     */
    private void changeOrderState(String payId, TbCfOrderVo oldOrder) {
        //更改订单状态
        TbCfItemOrderREntity itemOrderR = new TbCfItemOrderREntity();
        itemOrderR.setOrderId(oldOrder.getOrderId());
        itemOrderR.setUpdateTime(new Date());
        itemOrderR.setOrderStatus(OrderStatusEnum.PAID.getValue());
        itemOrderR.setDeliveryFlag(DeliveryStatusEnum.PROCESSING.getValue());
        tbCfItemOrderRDao.updates(itemOrderR);
        TbCfOrderEntity tbCfOrder = new TbCfOrderEntity();
        tbCfOrder.setOrderId(oldOrder.getOrderId());
        tbCfOrder.setUpdateTime(new Date());
        tbCfOrder.setDealTime(new Date());
        tbCfOrder.setPayId(payId);
        tbCfOrder.setOrderStatus(OrderStatusEnum.PAID.getValue());
        tbCfOrder.setPayStatus(OrderStatusEnum.PAID.getValue());
        tbCfOrderDao.update(tbCfOrder);
    }


    /**
     * 把订单从redis缓存删除
     *
     * @param tbCfOrderVo
     */
    private void removeRedisCache(TbCfOrderVo tbCfOrderVo) {
        orderRedisCache.delete(KeyConstant.ORDER_DET + tbCfOrderVo.getOrderId());
        String couponId = "";
        if (StringUtils.isNotBlank(tbCfOrderVo.getCouponId())) {
            couponId = tbCfOrderVo.getCouponId();
        }
        String orderIdAndCouponId = tbCfOrderVo.getOrderId() + ":" + tbCfOrderVo.getUserId() + ":" + couponId;
        orderRedisCache.delete(KeyConstant.ORDER_EXP + orderIdAndCouponId);
    }

    /**
     * 下单后
     * 1、将商品从购物车删除（伪删除）
     * 2、将商品id加入订单中
     * 3、把订单放redis中，过期则取消订单
     *
     * @param orderId
     * @param tbCfCartItemDetailList
     * @param definiteOrder
     */
    private void afterPlaceOrder(String orderId, List<TbCfCartItemDetailVo> tbCfCartItemDetailList, TbCfOrderVo definiteOrder) {
        //将商品从购物车删除（伪删除）
        deleteItemFromCart(tbCfCartItemDetailList);

        //将商品id加入订单中,查询订单中的商品
        updateItemOrderRecord(orderId, tbCfCartItemDetailList);
        //使用优惠券
        if (StringUtils.isNotBlank(definiteOrder.getCouponId())) {
            couponUse(definiteOrder.getUserId(), definiteOrder.getCouponId());
        }
        //把订单放redis中，过期则取消订单 RedisKeyExpirationListener接收
        long timeout = 1800;
        String timeoutStr = domainProperties.getProperty("redis.order.expiredTime");
        if (StringUtils.isNotBlank(timeoutStr)) {
            timeout = Long.valueOf(timeoutStr);
        }
        String couponId = "";
        if (StringUtils.isNotBlank(definiteOrder.getCouponId())) {
            couponId = definiteOrder.getCouponId();
        }
        String orderIdAndCouponId = orderId + ":" + definiteOrder.getUserId() + ":" + couponId;
        orderRedisCache.set(KeyConstant.ORDER_EXP + orderIdAndCouponId, definiteOrder.getRealityPay(), timeout);
        //订单保存一份在redis 后续支付的时候，可以使用
        orderRedisCache.set(KeyConstant.ORDER_DET + orderId, definiteOrder, timeout);

    }

    private void updateItemOrderRecord(String orderId, List<TbCfCartItemDetailVo> tbCfCartItemDetailList) {
        for (TbCfCartItemDetailVo tbCfCartItemDetailVo : tbCfCartItemDetailList) {
            TbCfItemOrderREntity tbCfItemOrderR = new TbCfItemOrderREntity();
            tbCfItemOrderR.setEnableFlag(StateConstant.VALID);
            tbCfItemOrderR.setItemId(tbCfCartItemDetailVo.getItemId());
            tbCfItemOrderR.setOrderId(orderId);
            tbCfItemOrderR.setUpdateTime(new Date());
            tbCfItemOrderR.setOrderStatus(OrderStatusEnum.PAID.getValue());
            tbCfItemOrderR.setDeliveryFlag(DeliveryStatusEnum.PROCESSING.getValue());
            tbCfItemOrderRDao.update(tbCfItemOrderR);
        }
    }

    /**
     * 使用优惠券
     *
     * @param userId
     * @param couponId
     */
    private void couponUse(String userId, String couponId) {
      /*  // 更新领取记录已领取
        int res = tbCfToiCouponDao.updateEnableFlag(userId, couponId, StateConstant.INVALID);
        if (res < 1) {
            logger.error("消费了优惠券，但是在数据表里没有记录！userId:" + userId + ";couponId:" + couponId);
        }*/
        /**
         * 增加已使用记录
         //         */
//        TbCfCouponUseEntity tbCfCouponUse = new TbCfCouponUseEntity();
//        tbCfCouponUse.setUseId(IdUtil.createIdbyUUID());
//        tbCfCouponUse.setCouponId(couponId);
//        tbCfCouponUse.setUserId(userId);
//        tbCfCouponUse.setUseTime(new Date());
//        tbCfCouponUseDao.save(tbCfCouponUse);

    }

    /**
     * 将商品id加入订单中
     *
     * @param orderId
     * @param tbCfCartItemDetailList
     */
   /* private void addItemOrderRecord(String orderId, List<TbCfCartItemDetailVo> tbCfCartItemDetailList) {
        List<TbCfItemOrderREntity> itemOrderRList = new ArrayList<>();
        for (TbCfCartItemDetailVo tbCfCartItemDetailVo : tbCfCartItemDetailList) {
            TbCfItemOrderREntity tbCfItemOrderR = new TbCfItemOrderREntity();
            tbCfItemOrderR.setOrderItemId(IdUtil.createIdbyUUID());
            tbCfItemOrderR.setEnableFlag(StateConstant.VALID);
            tbCfItemOrderR.setItemId(tbCfCartItemDetailVo.getItemId());
            tbCfItemOrderR.setOrderId(orderId);
            tbCfItemOrderR.setUpdateTime(new Date());
            tbCfItemOrderR.setOrderStatus(OrderStatusEnum.PAID.getValue());
            tbCfItemOrderR.setDeliveryFlag(DeliveryStatusEnum.PROCESSING.getValue());
            itemOrderRList.add(tbCfItemOrderR);
        }
        //int res =
        tbCfItemOrderRDao.saveBatch(itemOrderRList);
    }*/

    /**
     * 将商品从购物车删除（伪删除）
     *
     * @param tbCfCartItemDetailList
     */
    private void deleteItemFromCart(List<TbCfCartItemDetailVo> tbCfCartItemDetailList) {
        List<String> cartRecordIdArray = new ArrayList<>();
        for (TbCfCartItemDetailVo tbCfCartItemDetailVo : tbCfCartItemDetailList) {
            cartRecordIdArray.add(tbCfCartItemDetailVo.getCartRecordId());
        }
        String[] cartRecordIds = cartRecordIdArray.toArray(new String[0]);
        tbCfCartRecordRDao.deleteItems(cartRecordIds);
    }

    /**
     * 确定订单
     *
     * @param tbCfUserInfoVo
     * @param pageOrder
     * @return
     * @throws IOException
     * @throws URISyntaxException
     */
    private TbCfOrderVo ensureOrder(TbCfUserInfoVo tbCfUserInfoVo, TbCfOrderVo pageOrder, List<TbCfCartItemDetailVo> itemDetailList, String toitableId) {
        TbCfOrderVo definiteOrder = getGenericOrder(itemDetailList);

        /*//获取可以使用的优惠券，后续还有判断此订单是否可以使用
        List<TbCfCouponEntity> tbCfCouponList = tbCfCouponDao.queryUserAvailableCoupon(tbCfUserInfoVo.getUserId(), new Date());
        if (!tbCfCouponList.isEmpty()) {
            //分开可使用和不可使用优惠券
            separateCoupon(definiteOrder, tbCfCouponList);
            if (!definiteOrder.getUsableCouponList().isEmpty()) {
                //设置默认的优惠券
                //验证订单内数据是否有效，目前需要验证优惠券，因为优惠券由页面传入，只有优惠券的选择才会影响到最后的金额。
                //也就是说，目前页面只需要传优惠券id就可以了。
                TbCfCouponEntity usableCoupon = checkCoupon(pageOrder.getCouponId(), definiteOrder.getUsableCouponList());
                if (usableCoupon != null) {
                    definiteOrder.setCouponId(usableCoupon.getCouponId());
                    definiteOrder.setCouponTitle(usableCoupon.getCouponTitle());
                    definiteOrder.setCouponPrice(usableCoupon.getDeductAmount());
                }
            }
        }*/

        //计算实际需要付款
        countRealityPay(definiteOrder, toitableId);
        //获取订单地址
        String deliveryAddressId = pageOrder.getDeliveryAddressId();
        Validator.NOT_BLANK.validate("address", deliveryAddressId);
        TbCfAddressEntity tbCfAddressEntity = tbCfAddressDao.queryObject(deliveryAddressId);
        if (null == tbCfAddressEntity) {
            deliveryAddressId = null;
            Validator.NOT_BLANK.validate("address", deliveryAddressId);
        } else {
            definiteOrder.setDeliveryAddressId(tbCfAddressEntity.getAddressId());
            definiteOrder.setDeliveryAddress(tbCfAddressEntity.getAddressDetail());
            definiteOrder.setDeliveryName(tbCfAddressEntity.getDeliveryName());
            definiteOrder.setDeliveryPhone(tbCfAddressEntity.getPhone());
            ///////////////////////////////地址 END//////////////////////////////
            definiteOrder.setOrderId(IdUtil.createIdbyUUID());
            definiteOrder.setOrderNo(IdUtil.createLongIdByDate());
            definiteOrder.setOrderTime(new Date());
            definiteOrder.setUserId(tbCfUserInfoVo.getUserId());
            definiteOrder.setUserName(tbCfUserInfoVo.getNick());
            definiteOrder.setOrderStatus(OrderStatusEnum.PENDING_PAY.getValue());
            definiteOrder.setDeliveryFlag(DeliveryStatusEnum.PROCESSING.getValue());
            definiteOrder.setPayStatus(OrderStatusEnum.PENDING_PAY.getValue());
            definiteOrder.setEnableFlag(StateConstant.VALID);
        }
        return definiteOrder;
    }

    /**
     * 获取通用的订单信息
     *
     * @return
     */
    private TbCfOrderVo getGenericOrder(List<TbCfCartItemDetailVo> itemDetailList) {
        TbCfOrderVo genericOrder = new TbCfOrderVo();
        genericOrder.setItemDetailList(itemDetailList);
        //初始商品总价
        BigDecimal itemsPrice = BigDecimal.valueOf(0.00);
        BigDecimal totalExpressCost = BigDecimal.ZERO;
        for (TbCfCartItemDetailVo tbCfCartItemDetailVo : itemDetailList) {
            BigDecimal itemNum = BigDecimal.valueOf(tbCfCartItemDetailVo.getItemNum());
            BigDecimal itemSourcePrice = tbCfCartItemDetailVo.getItemPrice();
            itemsPrice = itemsPrice.add(itemSourcePrice.multiply(itemNum));
            //计算运费
            BigDecimal expressCost = getExpressTemplate(tbCfCartItemDetailVo.getItemCategory());
            //expressCost = expressCost.multiply(itemNum);
            if("1".equals(itemNum)){
                expressCost = expressCost.multiply(itemNum);
            }else{
                BigDecimal a= BigDecimal.valueOf(1);
                BigDecimal dj = expressCost.multiply(itemNum.subtract(a));
                expressCost =(dj.divide(BigDecimal.valueOf(2),0,BigDecimal.ROUND_UNNECESSARY)).add(expressCost);
            }
            totalExpressCost = totalExpressCost.add(expressCost);
        }
        //计算手续费
        BigDecimal fee = countFee(itemsPrice);
        //税费
        BigDecimal tax = countTax(itemsPrice);
        //商品总价
        BigDecimal totalPrice = itemsPrice.add(fee).add(tax).add(totalExpressCost);
        genericOrder.setTotalPrice(totalPrice);
        genericOrder.setItemsPrice(itemsPrice);
        genericOrder.setExpressCost(totalExpressCost);
        genericOrder.setTax(tax);
        genericOrder.setFee(fee);
        return genericOrder;
    }


    /**
     * 获取运费 TODO 运费模板可改为缓存
     *
     * @param templateId
     * @return
     */
    private BigDecimal getExpressTemplate(String templateId) {
        TbCfExpressTemplateEntity tbCfExpressTemplateEntity = tbCfExpressTemplateDao.queryObject(templateId);
        return tbCfExpressTemplateEntity.getExpressFee();
    }


    /**
     * 验证订单优惠券
     *
     * @param couponId
     * @param usableCouponList
     * @return
     */
    private TbCfCouponEntity checkCoupon(String couponId, List<TbCfCouponEntity> usableCouponList) {
        TbCfCouponEntity result = null;
        for (TbCfCouponEntity tbCfCouponEntity : usableCouponList) {
            if (couponId.equals(tbCfCouponEntity.getCouponId())) {
                result = tbCfCouponEntity;
            }

        }
        return result;
    }

    /**
     * 用户计算价格2
     *
     * @param tbCfUserInfoVo
     * @param tbCfCartItemDetailList
     * @return
     * @throws IOException
     * @throws URISyntaxException
     * @throws ExecutionException
     * @throws InterruptedException
     * @throws TimeoutException
     */
    private TbCfOrderVo getOrderData(TbCfUserInfoVo tbCfUserInfoVo, List<TbCfCartItemDetailVo> tbCfCartItemDetailList, String toitableId) throws IOException, URISyntaxException, ExecutionException, InterruptedException, TimeoutException {
        TbCfOrderVo tbCfOrder = getGenericOrder(tbCfCartItemDetailList);
       /* //获取可以使用的优惠券，后续还有判断此订单是否可以使用
       List<TbCfCouponEntity> tbCfCouponList = tbCfCouponDao.queryUserAvailableCoupon(tbCfUserInfoVo.getUserId(), new Date());

        if (!tbCfCouponList.isEmpty()) {
            //分开可使用和不可使用优惠券
            separateCoupon(tbCfOrder, tbCfCouponList);
            if (!tbCfOrder.getUsableCouponList().isEmpty()) {
                //设置默认的优惠券
                 setDefaultCoupon(tbCfOrder);
            }
        }*/

        //计算实际需要付款
        countRealityPay(tbCfOrder, toitableId);

        tbCfOrder.setUserId(tbCfUserInfoVo.getUserId());
        tbCfOrder.setUserName(tbCfUserInfoVo.getNick());

        return tbCfOrder;
    }

    /**
     * 计算实际付款
     *
     * @param tbCfOrder
     */
    private void countRealityPay(TbCfOrderVo tbCfOrder, String toitableId) {
        if (toitableId != null) {
            TbCfCouponEntity couponEntity = tbCfOrderDao.queryCouponPrice(toitableId);
            if (couponEntity != null) {
                tbCfOrder.setCouponPrice(couponEntity.getDeductAmount());
                tbCfOrder.setCouponId(couponEntity.getCouponId());
            }
        }
        BigDecimal couponPrice = tbCfOrder.getCouponPrice();
        //实际需要支付款项
        if (couponPrice != null) {
            BigDecimal realityPay = tbCfOrder.getTotalPrice().subtract(couponPrice);
            //比0小则等于0
            if (realityPay.compareTo(BigDecimal.ZERO) < 0) {
                realityPay = BigDecimal.ZERO;
            }
            tbCfOrder.setRealityPay(realityPay);
        } else {
            tbCfOrder.setRealityPay(tbCfOrder.getTotalPrice());
        }
        removeRedisCache(tbCfOrder);
        orderRedisCache.set(KeyConstant.ORDER_DET + tbCfOrder.getOrderId(), tbCfOrder);
    }

    /**
     * 分开可使用和不可使用优惠券(暂时没用)
     *
     * @param tbCfOrder
     * @param tbCfCouponList
     */
    private void separateCoupon(TbCfOrderVo tbCfOrder, List<TbCfCouponEntity> tbCfCouponList) {
        //可用优惠券
        List<TbCfCouponEntity> usableCouponList = new ArrayList<>();
        //不可用优惠券
        List<TbCfCouponEntity> unusableCouponList = new ArrayList<>();

        BigDecimal itemsPrice = tbCfOrder.getItemsPrice();
        for (TbCfCouponEntity tbCfCoupon : tbCfCouponList) {
            if (itemsPrice.compareTo(tbCfCoupon.getWithAmount()) >= 0) {
                usableCouponList.add(tbCfCoupon);
            } else {
                unusableCouponList.add(tbCfCoupon);
            }

        }
        tbCfOrder.setUsableCouponList(usableCouponList);
        tbCfOrder.setUnusableCouponList(unusableCouponList);
    }

    /**
     * 设置默认减免优惠券
     *
     * @param tbCfOrder
     */
    private void setDefaultCoupon(TbCfOrderVo tbCfOrder) {
        //可用优惠券
        List<TbCfCouponEntity> usableCouponList = tbCfOrder.getUsableCouponList();
        //根据抵扣金额排序 默认升序
        Collections.sort(usableCouponList, Comparator.comparing(TbCfCouponEntity::getDeductAmount));
        //倒序排列
        Collections.reverse(usableCouponList);
        tbCfOrder.setCouponId(usableCouponList.get(0).getCouponId());
        tbCfOrder.setCouponTitle(usableCouponList.get(0).getCouponTitle());
        tbCfOrder.setCouponPrice(usableCouponList.get(0).getDeductAmount());
    }

    /**
     * 计算税费
     *
     * @param itemsPrice
     * @return
     */
    private BigDecimal countTax(BigDecimal itemsPrice) {
        TbCfTaxEntity tbCfTax = tbCfTaxDao.getAvailableFee();
        BigDecimal tax = BigDecimal.ZERO;
        if (tbCfTax != null) {
            tax = itemsPrice.multiply(tbCfTax.getTaxRate());
            tax = tax.setScale(2, BigDecimal.ROUND_UP);
        }
        return tax;
    }

    /**
     * 计算手续费
     *
     * @param itemsPrice
     * @return
     */
    private BigDecimal countFee(BigDecimal itemsPrice) {
        TbCfFeeEntity tbCfFee = tbCfFeeService.getAvailableFee();
        BigDecimal fee = BigDecimal.ZERO;
        if (tbCfFee != null) {
            fee = itemsPrice.multiply(tbCfFee.getFeePercent());
            fee = fee.setScale(2, BigDecimal.ROUND_UP);
        }
        return fee;
    }
}
