/**
 * Description: CmOrder业务实现类
 * Copyright:   Copyright (c)2015
 * Company:     江苏三六五网络股份有限公司
 *
 * @author: 江苏三六五网络股份有限公司
 * @version: 1.0
 * Create at:   2015-08-10 下午 17:06:17
 * <p/>
 * Modification History:
 * Date         Author      Version     Description
 * ------------------------------------------------------------------
 * 2015-08-10   江苏三六五网络股份有限公司   1.0         Initial
 */
package com.house365.ws.service.impl;

import java.text.SimpleDateFormat;
import java.util.*;

import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.house365.beans.entity.*;
import com.house365.rest.context.CmConstant;
import com.house365.rest.exception.ServiceRunException;
import com.house365.web.util.StringUtils;
import com.house365.ws.cached.RedisUtilsInterface;
import com.house365.ws.dao.interfaces.*;
import com.house365.ws.service.interfaces.ICmPromotionService;
import com.house365.ws.service.interfaces.ICmUserService;
import com.house365.ws.util.Constant;
import org.hibernate.impl.CriteriaImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.house365.beans.system.QueryParams;
import com.house365.beans.vo.CmOrderVo;
import com.house365.dao.system.interfaces.Dao;
import com.house365.service.system.impl.DefaultServiceImpl;
import com.house365.ws.interfaces.rest.OrderSubmitInterfaceImpl;
import com.house365.ws.service.interfaces.ICmOrderService;
import com.house365.ws.util.DateUtils;

/**
 * CmOrder业务实现类<br>
 *
 * @author 江苏三六五网络股份有限公司
 * @version 1.0, 2015-08-10
 * @see
 * @since 1.0
 */
@Service("cmOrderService")
public class CmOrderServiceImpl<T extends CmOrderEntity> extends DefaultServiceImpl<T> implements ICmOrderService<T> {
    /**
     * 日志记录器
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(CmOrderServiceImpl.class);

    /**
     * 自动注入的数据访问对象
     */
    @Autowired
    private ICmOrderDao<T> cmOrderDao;
    @Autowired
    private ICmCreditGoodsDao<CmCreditGoodsEntity> cmCreditGoodsDao;
    @Autowired
    private ICmUserDao<CmUserEntity> cmUserDao;
    @Autowired
    private ICmCreditRecordDao<CmCreditRecordEntity> cmCreditRecordDao;
    @Autowired
    private ICmExchangeCodeDao<CmExchangeCodeEntity> cmExchangeCodeDao;
    @Autowired
    private ICmPromotionService promotionService;
    @Autowired
    private ICmUserService cmUserService;

    /**
     * 周期内最多订单数, 默认2次
     */
    @Value("#{system.orderLimitCount}")
    private Integer ORDER_LIMIT_COUNT = 0;
    /**
     * 订单周期
     */
    @Value("#{system.orderLimitCircle}")
    private Integer ORDER_LIMIT_CIRCLE = 0;

    @Override
    protected Dao<T> getDao() {
        return cmOrderDao;
    }

    @Autowired
    RedisUtilsInterface redisUtils;

    static final String key = "order:ThisMonthCount:";

    public ICmOrderDao<T> getCmOrderDao() {
        return cmOrderDao;
    }

    public void setCmOrderDao(ICmOrderDao<T> cmOrderDao) {
        this.cmOrderDao = cmOrderDao;
    }

    @Override
    public List<CmOrderEntity> getCmOrderStatisticsList(QueryParams<CmOrderEntity> queryParams) {

        return cmOrderDao.getCmOrderStatisticsList(queryParams);
    }

    /**
     * 功能描述: 首次校验<br>
     * 一个月内的订单提交次数是否过期
     *
     * @return true 超过限购数量 false 没有超过
     * @author yinchangming
     * @version [v1.0.0, 2015年10月27日]
     * @since [产品/模块版本](可选)
     */
    @Override
    public boolean isOrderOutOfLimits(CmUserEntity userEntity) {
        //统计限购商品数, 不限购商品和限购商品可互相转换，所以订单商品信息需要实时查询，缓存数据更新统计比较麻烦，暂不缓存用户限购商品购买数量
        final Integer userId = userEntity.getId();
        int size = getLimitOrderSize(userId);
        return size >= ORDER_LIMIT_COUNT;
    }

    //订单保存后，二次校验，如果超出,删除订单
    @Override
    public boolean isOrderOutOfLimitSecond(CmUserEntity userEntity) {
        //统计限购商品数, 不限购商品和限购商品可互相转换，所以订单商品信息需要实时查询，缓存数据更新统计比较麻烦，暂不缓存用户限购商品购买数量
        final Integer userId = userEntity.getId();
        int size = getLimitOrderSize(userId);
        return size > ORDER_LIMIT_COUNT;
    }

    private int getLimitOrderSize(Integer userId) {
        int size = 0;
        Date nowDate = new Date();
        //30天内
        Date newDate = DateUtils.getSeveralDaysBefore(ORDER_LIMIT_CIRCLE);
        QueryParams<CmOrderEntity> queryParams = new QueryParams<>();
        Map<String, Object> map = new HashMap<>();
        map.put("GT_createTime", newDate);
        map.put("LT_andCreateTime", nowDate);
        map.put("EQ_userId", userId);
        queryParams.setSearchParams(map);
        List<CmOrderEntity> list = (List<CmOrderEntity>) cmOrderDao.queryAll(queryParams);

        if (list != null && !list.isEmpty()) {
            for (CmOrderEntity order : list) {
                //此处可优化，在订单中记录是否限购商品
                CmCreditGoodsEntity cmCreditGood = cmCreditGoodsDao.getById(order.getGoodsId());
                if (cmCreditGood != null && cmCreditGood.getIsBuyLimit() == 1) {
                    size += 1;
                }
            }
        }
        return size;
    }

    private int getCurrentMonth(Date nowDate) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(nowDate);
        return calendar.get(Calendar.MONTH) + 1;
    }

    /**
     * 功能描述: <br>
     * 指定用户30天内的订单提交次数
     *
     * @return 30天内的订单提交次数
     * @since [产品/模块版本](可选)
     */
    @Override
    public Map<String, Integer> userOrderCountInCircle(CmUserEntity userEntity) {
        Map<String, Integer> map = new HashMap<>();
        List<T> list = getThisMonthOrders(userEntity);
        int allOrderCount = 0;
        int limitProductOrderCount = 0;

        if (list != null) {
            allOrderCount = list.size();
            for (CmOrderEntity order : list) {
                CmCreditGoodsEntity good = cmCreditGoodsDao.getById(order.getGoodsId());
                if (good != null && good.getIsBuyLimit() == 1) {
                    limitProductOrderCount += 1;
                }
            }
        }

        map.put("allOrderCount", allOrderCount);
        map.put("limitProductOrderCount", limitProductOrderCount);

        return map;
    }

    private List<T> getThisMonthOrders(CmUserEntity userEntity) {
        Date nowDate = new Date();
        //30天内订单数
        Date newDate = DateUtils.getSeveralDaysBefore(ORDER_LIMIT_CIRCLE);
        QueryParams<CmOrderEntity> queryParams = new QueryParams<>();
        Map<String, Object> map = new HashMap<>();
        map.put("GT_createTime", newDate);
        map.put("LT_andCreateTime", nowDate);
        map.put("EQ_userId", userEntity.getId());
        queryParams.setSearchParams(map);
        return cmOrderDao.queryAll(queryParams);
    }

    @SuppressWarnings("unchecked")
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    @Override
    public Map<String, Object> transUpdateOrderStockIntegral(CmOrderVo orderVo) throws ServiceRunException {
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("orderCode", -10000);
        resultMap.put("msg", "创建订单异常！");
        try {
            //处理商品库存,被兑换次数
            CmCreditGoodsEntity creditGoodsEntity = orderVo.getCreditGoodsEntity();
            Integer stock = creditGoodsEntity.getStock();
            creditGoodsEntity.setStock(stock - 1);
            creditGoodsEntity.setExchangedCount(creditGoodsEntity.getExchangedCountNotZero() + 1);

            CmOrderEntity orderEntity = orderVo.getEntity();
            orderEntity.setDeliverTime(orderVo.getCreditGoodsEntity().getStartTime());
            orderEntity.setReceiveTime(orderVo.getCreditGoodsEntity().getEndTime());

            CmExchangeCodeEntity exchangeCodeEntity = null;
            if ("1".equals(creditGoodsEntity.getGoodsType())) {
                //获取虚拟商品兑换码
                exchangeCodeEntity = cmExchangeCodeDao.getFirstByStatusAndGoodsId(0, orderVo.getEntity().getGoodsId());
                if (exchangeCodeEntity != null) {
                    //更新该条数据兑换码状态为已兑换
                    exchangeCodeEntity.setStatus(1);//已兑换
                    exchangeCodeEntity.setExchangeTime(new Date());
                    //获取兑换码
                    String exchangeCode = exchangeCodeEntity.getExchangeCode();
                    //获取有效期
                    String startTime = parseDate(orderVo.getCreditGoodsEntity().getStartTime(), "yyyy-MM-dd");
                    String endTime = parseDate(orderVo.getCreditGoodsEntity().getEndTime(), "yyyy-MM-dd");
                    resultMap.put("exchangeCode", exchangeCode);
                    resultMap.put("validTime", startTime + "至" + endTime);
                    orderEntity.setOerderNumber(exchangeCode);
                    orderEntity.setDeliverTime(orderVo.getCreditGoodsEntity().getStartTime());
                    orderEntity.setReceiveTime(orderVo.getCreditGoodsEntity().getEndTime());
                } else {
                    resultMap.put("orderCode", -10000);
                    resultMap.put("msg", "无可用兑换码！");
                    return resultMap;
                }
            }

            //订单入库
            Integer orderId = cmOrderDao.save((T) orderEntity);
            if (null != orderId) {

                //获取当月的次数 防止高并发超卖，再校验一次
                if (1 == creditGoodsEntity.getIsBuyLimit() && isOrderOutOfLimitSecond(orderVo.getUserEntity())) {
                    LOGGER.warn("oversell rollback orderEntity : [{}]", orderEntity);
                    //删除超卖订单
                    cmOrderDao.delete(orderId);
                    throw new ServiceRunException("30天内只能兑换" + ORDER_LIMIT_COUNT + "次哟!");
                }

                if ("1".equals(creditGoodsEntity.getGoodsType())) {
                    //更新虚拟商品兑换码状态
                    cmExchangeCodeDao.update(exchangeCodeEntity);
                }

                //用户本月订单数缓存加1
                //                String thisKey = key + getCurrentMonth(new Date()) + ":" + orderVo.getUserEntity().getId();
                //                String cacheCount = redisUtils.getValByKeyNew(thisKey);
                //                int countInt = Integer.parseInt(cacheCount == null ? "0" : String.valueOf(cacheCount));
                //                redisUtils.getSet(thisKey, String.valueOf(countInt + 1));
                //                LOGGER.debug("======= order save , orderId is {}, cacheCount is {}", orderId,
                //                             redisUtils.getValByKeyNew(thisKey));

                //更新库存
                // System.out.println("线程:"+iiCount+"---"+new Date().getTime()+"---"+userEntity.getUserName()+"----"+userEntity.getUserId()+"---开始更新"+creditGoodsEntity.toString());
                cmCreditGoodsDao.update(creditGoodsEntity);

                //System.out.println("线程:"+iiCount+"---"+new Date().getTime()+"---"+userEntity.getUserName()+"----"+userEntity.getUserId()+"---结束更新"+creditGoodsEntity.toString());
                //更新用户积分
                cmUserDao.update(orderVo.getUserEntity());
                //新增积分记录
                CmCreditRecordEntity creditRecordEntity = orderVo.getCreditRecordEntity();
                creditRecordEntity.setOrderId(orderId);
                cmCreditRecordDao.save(creditRecordEntity);

                cmUserService.clearUserCache(orderVo.getUserEntity().getUserId());
            }

            resultMap.put("orderId", orderId);
            resultMap.put("orderCode", 10000);
            resultMap.put("msg", "订单创建成功！");

        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            throw new ServiceRunException(e.getMessage());
        }
        return resultMap;
    }

    public static String parseDate(Date date, String format) {
        SimpleDateFormat dateformat = new SimpleDateFormat(format);
        return dateformat.format(date);
    }

    public static Date parseDate(String datestr, String format) {
        SimpleDateFormat df = new SimpleDateFormat(format);
        Date date = null;
        try {
            date = df.parse(datestr);
        } catch (java.text.ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

}
