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

import com.house365.beans.constant.CommentConstant;
import com.house365.beans.entity.*;
import com.house365.beans.system.QueryParams;
import com.house365.beans.vo.CmHouseCommentVo;
import com.house365.dao.system.interfaces.Dao;
import com.house365.rest.context.CmConstant;
import com.house365.service.system.impl.DefaultServiceImpl;
import com.house365.web.util.DateTimeUtils;
import com.house365.web.util.SpringContextUtil;
import com.house365.ws.beans.response.CmDictionaryResponse;
import com.house365.ws.cached.RedisUtilsInterface;
import com.house365.ws.dao.interfaces.*;
import com.house365.ws.interfaces.server.ICmDictionary;
import com.house365.ws.service.interfaces.ICmHouseCommentService;
import com.house365.ws.service.interfaces.ICmHouseService;
import com.house365.ws.util.PhpInterfaceUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * CmHouseComment业务实现类<br>
 *
 * @author 江苏三六五网络股份有限公司
 * @version 1.0, 2015-08-10
 * @see
 * @since 1.0
 */
@Service("cmHouseCommentService")
public class CmHouseCommentServiceImpl<T extends CmHouseCommentEntity> extends DefaultServiceImpl<T> implements ICmHouseCommentService<T> {

    private static final Logger HOUSECOMMENTLOGGER = LoggerFactory.getLogger("InterfaceLog");

    /**
     * 自动注入的数据访问对象
     */
    @Autowired
    private ICmHouseCommentDao<T> cmHouseCommentDao;

    @Autowired
    private ICmUserDao<CmUserEntity> userDao;
    @Autowired
    private ICmHouseDao<CmHouseEntity> houseDao;
    @Autowired
    private ICmCreditRecordDao<CmCreditRecordEntity> creditRecordDao;
    @Autowired
    private ICmCreditRuleDao<CmCreditRuleEntity> creditRuleDao;
    @Autowired
    private ICmHouseService cmHouseService;

    @Autowired
    private RedisUtilsInterface redisUtilsInterface;

    @Autowired
    private ICmDictionary cmDictionary;

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

    @Override
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    public CmHouseCommentVo transHouseComment(Map<String, Object> map) throws Exception {
        CmHouseCommentVo resultVo = new CmHouseCommentVo();

        // 楼盘Id
        String houseId = null;
        //楼盘物业类型
        Integer channel = null;
        // 评论内容
        String criticContent = null;
        // 评论图片
        String criticPictures = null;
        // 价格评分
        String priceScore = null;
        // 地段评分
        String placeScore = null;
        // 交通评分
        String trafficScore = null;
        // 配套评分
        String infrastructureScore = null;
        // 环境评分
        String environmentScore = null;
        // 是否匿名
        String isAnonymous = null;
        // 城市key
        String cityKey = null;

        //评论来源
        int source = 0;

        try {
            CmHouseCommentEntity entity = new CmHouseCommentEntity();

            if (!StringUtils.isEmpty(map.get(CmConstant.HOUSEID))) {
                houseId = ((String[]) map.get(CmConstant.HOUSEID))[0];
            }
            if (!StringUtils.isEmpty(map.get(CmConstant.CHANNEL))) {
                channel = Integer.parseInt(((String[]) map.get(CmConstant.CHANNEL))[0]);
            }
            if (!StringUtils.isEmpty(map.get(CmConstant.criticContent))) {
                criticContent = ((String[]) map.get(CmConstant.criticContent))[0];
            }
            if (!StringUtils.isEmpty(map.get(CmConstant.criticPictures))) {
                criticPictures = ((String[]) map.get(CmConstant.criticPictures))[0];
            }
            if (!StringUtils.isEmpty(map.get(CmConstant.priceScore))) {
                priceScore = ((String[]) map.get(CmConstant.priceScore))[0];
                entity.setPriceScore(Float.parseFloat(priceScore));
            }
            if (!StringUtils.isEmpty(map.get(CmConstant.placeScore))) {
                placeScore = ((String[]) map.get(CmConstant.placeScore))[0];
                entity.setPlaceScore(Float.parseFloat(placeScore));
            }
            if (!StringUtils.isEmpty(map.get(CmConstant.trafficScore))) {
                trafficScore = ((String[]) map.get(CmConstant.trafficScore))[0];
                entity.setTrafficScore(Float.parseFloat(trafficScore));
            }
            if (!StringUtils.isEmpty(map.get(CmConstant.infrastructureScore))) {
                infrastructureScore = ((String[]) map.get(CmConstant.infrastructureScore))[0];
                entity.setInfrastructureScore(Float.parseFloat(infrastructureScore));
            }
            if (!StringUtils.isEmpty(map.get(CmConstant.environmentScore))) {
                environmentScore = ((String[]) map.get(CmConstant.environmentScore))[0];
                entity.setEnvironmentScore(Float.parseFloat(environmentScore));
            }
            if (!StringUtils.isEmpty(map.get(CmConstant.isAnonymous))) {
                isAnonymous = ((String[]) map.get(CmConstant.isAnonymous))[0];
                entity.setIsAnonymous(Integer.valueOf(isAnonymous));
            }
            if (!StringUtils.isEmpty(map.get(CmConstant.SOURCE))) {
                source = Integer.parseInt(((String[]) map.get(CmConstant.SOURCE))[0]);
                entity.setSource(source);
            } else {
                entity.setIsAnonymous(null);
            }
            if (!StringUtils.isEmpty(map.get(CmConstant.CITY_KEY))) {
                cityKey = ((String[]) map.get(CmConstant.CITY_KEY))[0];
            }

            //获取用户信息
            CmDictionaryResponse forbidCityResponse = cmDictionary.getCmDictionaryById(16);
            boolean needCheck = false;
            String cityList = "";
            if (null != forbidCityResponse.getEntity()) {
                CmDictionaryEntity dictionaryEntity = forbidCityResponse.getEntity();
                cityList = "," + dictionaryEntity.getDicValue() + ",";

            }

            CmUserEntity userEntity = (CmUserEntity) map.get("currentUserEntity");

            entity.setCommentAmount(0);
            entity.setCommentDate(new Date());
            entity.setCriticContent(criticContent);
            entity.setCriticId(userEntity.getId());
            entity.setCriticName(userEntity.getUserName());
            entity.setCriticPhone(userEntity.getPhoneNumber());
            entity.setCriticPictures(criticPictures);

            CmHouseEntity houseEntity = houseDao.getHouseByHouseId(Integer.valueOf(houseId), cityKey, channel);
            //根据houseId获取本地库里的楼盘信息，为空则调用接口获取楼盘信息并插入本地库
            if (houseEntity != null) {
                entity.setHouseName(houseEntity.getHouseName());
                //修改楼盘表相关信息
                //评分计算公式   (评论评分*楼盘总评论数+楼盘当前评分)/(楼盘总评论数+1)
                float houseEnvironmentScore = (houseEntity.getEnviromentScore() * houseEntity.getTotolCommetAmount() + Float.parseFloat(
                        environmentScore)) / (houseEntity.getTotolCommetAmount() + 1);
                float housePlaceScore = (houseEntity.getPlaceScore() * houseEntity.getTotolCommetAmount() + Float.parseFloat(
                        placeScore)) / (houseEntity.getTotolCommetAmount() + 1);
                float housePriceScore = (houseEntity.getPriceScore() * houseEntity.getTotolCommetAmount() + Float.parseFloat(
                        priceScore)) / (houseEntity.getTotolCommetAmount() + 1);
                float houseInfrastructureScore = (houseEntity.getInfrastructureScore() * houseEntity.getTotolCommetAmount() + Float.parseFloat(
                        infrastructureScore)) / (houseEntity.getTotolCommetAmount() + 1);
                float houseTrafficScore = (houseEntity.getTrafficScore() * houseEntity.getTotolCommetAmount() + Float.parseFloat(
                        trafficScore)) / (houseEntity.getTotolCommetAmount() + 1);

                houseEntity.setEnviromentScore(houseEnvironmentScore);
                houseEntity.setPlaceScore(housePlaceScore);
                houseEntity.setPriceScore(housePriceScore);
                houseEntity.setInfrastructureScore(houseInfrastructureScore);
                houseEntity.setTrafficScore(houseTrafficScore);

                float integrationScore = houseEnvironmentScore + housePlaceScore + housePriceScore + houseInfrastructureScore + houseTrafficScore;

                BigDecimal b6 = BigDecimal.valueOf(integrationScore);
                integrationScore = b6.setScale(1, BigDecimal.ROUND_HALF_UP).floatValue() / 5;
                houseEntity.setIntegrationScore(integrationScore);

                if (cityList.contains("," + houseEntity.getCityKey() + ",")) {
                    needCheck = true;
                }

                if (!needCheck) {
                    houseEntity.setTotolCommetAmount(houseEntity.getTotolCommetAmount() + 1);
                    if (criticPictures != null && criticPictures.length() > 5) {
                        houseEntity.increaseWithPictureCount();
                    }
                }

                if (houseEntity.getEarliestComment() == null) {
                    houseEntity.setEarliestComment(new Date());
                }

                houseDao.update(houseEntity);

            } else {
                houseEntity = PhpInterfaceUtils.getHouseByRemoteInterface(houseId, cityKey, channel);

                if (houseEntity == null) {
                    resultVo.setResultCode("2");
                    return resultVo;
                }
                entity.setHouseName(houseEntity.getHouseName());
                houseEntity.setEnviromentScore(Float.parseFloat(environmentScore));
                houseEntity.setPlaceScore(Float.parseFloat(placeScore));
                houseEntity.setPriceScore(Float.parseFloat(priceScore));
                houseEntity.setInfrastructureScore(Float.parseFloat(infrastructureScore));
                houseEntity.setTrafficScore(Float.parseFloat(trafficScore));
                houseEntity.setChannel(channel);
                float integrationScore = Float.parseFloat(environmentScore) + Float.parseFloat(
                        placeScore) + Float.parseFloat(priceScore) + Float.parseFloat(
                        infrastructureScore) + Float.parseFloat(trafficScore);

                houseEntity.setIntegrationScore(integrationScore / 5);
                houseEntity.setEarliestComment(new Date());

                if (cityList.contains("," + houseEntity.getCityKey() + ",")) {
                    needCheck = true;
                }

                if (!needCheck) {
                    houseEntity.setTotolCommetAmount(1);
                    if (criticPictures != null && criticPictures.length() > 5) {
                        houseEntity.increaseWithPictureCount();
                    }
                }

                int id = houseDao.save(houseEntity);
                houseEntity.setId(id);

            }

            //装配评论数据
            entity.setHouseId(houseEntity.getId());
            entity.setHouseName(houseEntity.getHouseName());
            entity.setIsDeleted(0);
            entity.setIsExcellent(0);
            entity.setIsReaded(0);
            entity.setIsReported(0);
            entity.setUserPhoto(userEntity.getUserPhoto());
            entity.setIsSticked(0);
            entity.setSource(source);
            entity.setPraiseAmount(0);
            entity.setCityKey(houseEntity.getCityKey());
            entity.setCityName(houseEntity.getCityName());

            if (needCheck) {
                entity.setCheckStatus(0);
            } else {
                entity.setCheckStatus(1);
            }

            float averageScore = Float.parseFloat(priceScore) + Float.parseFloat(trafficScore) + Float.parseFloat(
                    placeScore) + Float.parseFloat(infrastructureScore) + Float.parseFloat(environmentScore);

            entity.setAverageScore(averageScore / 5);
            entity.setCriticId(userEntity.getId());
            //添加评论表数据
            Integer commentId = this.save((T) entity);
            entity.setId(commentId);
            resultVo.setEntity(entity);

            //clear cache of housecomment
            final Integer id = entity.getHouseId();
            ExecutorService fixedThreadPool = Executors.newFixedThreadPool(1);
            fixedThreadPool.submit(new Runnable() {
                @Override
                public void run() {
                    removeCache(id);
                }
            });

            //只有app记录积分
            if (needCheck || CommentConstant.COMMENT_SOURCE_APP != source) {
                resultVo.setResultCode("1");
                return resultVo;
            }

            Integer userId = userEntity.getId();
            Integer houseEntityId = houseEntity.getId();

            //change user credit
            CmHouseCommentVo result = doChangeUserCredit(commentId, userId, houseEntityId);
            resultVo.setResultCode(result.getResultCode());
            return resultVo;

        } catch (Exception e) {
            HOUSECOMMENTLOGGER.error(e.getMessage(), e);
            throw e;
        }
    }

    //change user credit
    @Override
    public CmHouseCommentVo doChangeUserCredit(
            Integer commentId, Integer userId, Integer houseEntityId
    ) throws Exception {
        CmHouseCommentVo resultVo = new CmHouseCommentVo();

        //如果评论过楼盘，则不继续加分
        QueryParams<CmHouseCommentEntity> qp = new QueryParams<>();
        Map<String, Object> searchParams = new HashMap<>();
        searchParams.put("EQ_criticId", userId);
        searchParams.put("EQ_houseId", houseEntityId);
        searchParams.put("EQ_checkStatus", "1");
        searchParams.put("NOTEQ_id", commentId);
        qp.setSearchParams(searchParams);
        List list = cmHouseCommentDao.queryAll(qp);
        if (list.size() > 0) {
            //如果已经评论过该楼盘，则没有积分
            resultVo.setResultCode("1");
            return resultVo;
        }

        //如果评论超过限定次数，则没有积分
        if (isCommentCountExceedLimit(userId)) {
            resultVo.setResultCode("1");
            return resultVo;
        }

        CmUserEntity userEntity = userDao.getById(userId);
        //添加积分记录
        CmCreditRecordEntity recordEntity = creditRecordDao.saveHouseCommentRecord(userEntity, commentId);
        //积分余额
        Integer remainingAmount = userEntity.getCredits() + recordEntity.getAmount();
        //对用户表积分余额进行操作
        userEntity.setCredits(remainingAmount);
        userDao.update(userEntity);
        resultVo.setResultCode("1");
        return resultVo;

    }

    @Override
    public List<CmHouseCommentEntity> transHouseCommentList(QueryParams<CmHouseCommentEntity> queryParams) {
        List<CmHouseCommentEntity> list = new ArrayList<>();
        try {
            list = (List<CmHouseCommentEntity>) cmHouseCommentDao.queryByPage(queryParams);
        } catch (Exception e) {
            HOUSECOMMENTLOGGER.error(e.getMessage(), e);
        }

        return list;
    }

    /**
     * clear cache of housecomment
     *
     * @param houseId house主键ID
     */
    @Override
    public void removeCache(Integer houseId) {
        CmHouseEntity house = (CmHouseEntity) cmHouseService.getById(houseId);
        if (null != house) {
            Integer id = house.getHouseId();
            final String cache_keys = id + "_commentKeysKey";
            RedisUtilsInterface redisUtils = (RedisUtilsInterface) SpringContextUtil.getBean("redisUtils");
            Set<Serializable> keys = redisUtils.getSetMember(cache_keys);
            if (keys != null && !keys.isEmpty()) {
                for (Serializable k : keys) {
                    redisUtils.deleteByKeyNew(String.valueOf(k));
                    redisUtils.setRemove(cache_keys, String.valueOf(k));
                }
            }
        }
    }

    @Override
    public Integer transDeleteHouseComment(String id, String isNoTalk) {
        // TODO Auto-generated method stub
        return null;
    }


    /**
     * 校验是否超出限制
     * 功能描述: <br>
     * 〈功能详细描述〉
     *
     * @return
     * @author yinchangming
     * @version [v1.0.0, 2015年8月31日]
     * @since [产品/模块版本](可选)
     */
    private boolean isCommentCountExceedLimit(Integer userId) {

        if (userId == null) {
            return false;
        }

        //校验是否超出限制
        CmCreditRuleEntity ruleEntity = creditRuleDao.getById(CmConstant.CREDITS_RULE_HOUSE_COMMENT);
        if (ruleEntity == null) {
            HOUSECOMMENTLOGGER.error("没有设置积分获取规则，返回否");
            return false;
        }

        int countLimit = ruleEntity.getCountLimit();
        int dayCircle = ruleEntity.getCountCircle();

        QueryParams<CmHouseCommentEntity> queryParams = new QueryParams<>();
        //默认当天
        Date beginDate;
        if (7 == dayCircle) {
            //周期为一周 取周一
            beginDate = DateTimeUtils.getFirstDayOfWeek(new Date());
        } else if (30 == dayCircle) {
            //周期为一月 取一号
            beginDate = DateTimeUtils.getFirstDayOfMonth(new Date());
        } else if (1 == dayCircle) {
            //周期为一天 取当天
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);
            beginDate = calendar.getTime();
        } else {
            //其他 前推指定天数
            beginDate = DateTimeUtils.getDaysAgo(new Date(), dayCircle);
        }

        Map<String, Object> searchParams = new HashMap<>();
        searchParams.put("GTE_happenTime", beginDate);
        searchParams.put("EQ_userId", userId);
        searchParams.put("EQ_ruleId", CmConstant.CREDITS_RULE_HOUSE_COMMENT);
        queryParams.setSearchParams(searchParams);
        //List<CmHouseCommentEntity> commentList = houseCommentService.queryAll(queryParams);
        int totalCount = creditRecordDao.getTotalCount(queryParams);
        if (totalCount >= countLimit) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 一个楼盘15分钟内只能评一次,每天只能评5个楼盘
     *
     * @param userId
     * @param houseId
     * @return
     */
    @Override
    public boolean checkCountNum(Integer userId, Integer houseId) {
        boolean flag = true;

        if (userId == null || houseId == null) {
            return flag;
        }

        Calendar yesterday = Calendar.getInstance();
        yesterday.set(Calendar.HOUR_OF_DAY, 0);
        yesterday.set(Calendar.MINUTE, 0);
        yesterday.set(Calendar.SECOND, 0);
        yesterday.set(Calendar.MILLISECOND, 0);
        List list = new ArrayList();

        if (houseId > 0) {
            Calendar cal = Calendar.getInstance();
            cal.add(Calendar.MINUTE, -15);
            QueryParams<CmHouseCommentEntity> qp = new QueryParams<>();
            Map<String, Object> searchParams = new HashMap<>();
            searchParams.put("EQ_criticId", userId);
            searchParams.put("EQ_houseId", houseId);
            searchParams.put("GTE_commentDate", cal.getTime());
            qp.setSearchParams(searchParams);
            list = cmHouseCommentDao.queryAll(qp);
        }

        QueryParams<CmHouseCommentEntity> qp1 = new QueryParams<>();
        Map<String, Object> searchParams1 = new HashMap<>();
        searchParams1.put("EQ_criticId", userId);
        searchParams1.put("GTE_commentDate", yesterday.getTime());
        searchParams1.put("NOTEQ_houseId", houseId);

        qp1.setSearchParams(searchParams1);
        int todayComment = cmHouseCommentDao.getDistinctHouseCount(qp1);

        if ((list != null && list.size() > 0) || todayComment >= 5) {
            flag = false;
        }

        return flag;
    }


}
