package com.house365.ws.interfaces.rest;

import com.google.common.base.Strings;
import com.house365.beans.entity.CmAssessEntity;
import com.house365.beans.entity.CmAssessScoreEntity;
import com.house365.beans.system.Page;
import com.house365.beans.system.QueryParams;
import com.house365.rest.context.CmConstant;
import com.house365.rest.context.Parameter;
import com.house365.rest.exception.IllegalServiceParameterException;
import com.house365.rest.exception.ServiceRunException;
import com.house365.web.util.SpringContextUtil;
import com.house365.web.util.StringUtils;
import com.house365.ws.cached.RedisUtilsInterface;
import com.house365.ws.dao.interfaces.ICmAssessDao;
import com.house365.ws.dao.interfaces.ICmAssessScoreDao;
import com.house365.ws.system.ReturnAppResult;
import com.house365.ws.util.*;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.math.NumberUtils;
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 javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * REST 接口
 * 房价评估接口
 */
@Service("assessInterface")
public class AssessInterface implements IAssessInterface {

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

    @Autowired
    private ICmAssessDao<CmAssessEntity> cmAssessDao;

    @Autowired
    private ICmAssessScoreDao<CmAssessScoreEntity> cmAssessScoreDao;

    @Autowired
    RedisUtilsInterface redisUtils;

    private final String version = "6.1.9";

    @Value("${newHouse.url}")
    private String newHouseUrl;

    /**
     * 保存评估记录
     *
     * @param paramMap 参数
     * @return 执行结果
     */
    @Override
    public Object saveAssess(Map<String, Object> paramMap) {
        JSONObject jsonObject = new JSONObject();
        try {
            paramMap.put("createTime", new Date());
            CmAssessEntity cmAssessEntity = new CmAssessEntity();
            cmAssessEntity.setTotalPrice(new BigDecimal(0));
            cmAssessEntity.setUnitPrice(new BigDecimal(0));
            cmAssessEntity.setStatus("1");
            checkInterfaceParameter(paramMap, cmAssessEntity);
            JSONObject calculateResult = DataCenterAssessUtil.calculatePrice(cmAssessEntity.getCity(),
                    cmAssessEntity.getBlockId(),
                    cmAssessEntity.getForward(),
                    cmAssessEntity.getRoom(),
                    cmAssessEntity.getBuildArea(),
                    cmAssessEntity.getFloor(),
                    cmAssessEntity.getTotalFloor());

            String unitPrice = (calculateResult == null || calculateResult.get(
                    "averprice") == null) ? "0" : String.valueOf(calculateResult.get("averprice"));
            String price = (calculateResult == null || calculateResult.get("price") == null) ? "0" : String.valueOf(
                    calculateResult.get("price"));

            BigDecimal up = new BigDecimal(unitPrice);
            BigDecimal pr = new BigDecimal(price);
            cmAssessEntity.setUnitPrice(up.setScale(0, BigDecimal.ROUND_HALF_UP));
            cmAssessEntity.setTotalPrice(pr.setScale(1, BigDecimal.ROUND_HALF_UP));

            //评估失败不保存
            Integer id;
            if (up.compareTo(new BigDecimal(0)) > 0 && pr.compareTo(new BigDecimal(0)) > 0) {
                if (cmAssessEntity.getId() != null) {
                    id = cmAssessEntity.getId();
                    cmAssessDao.update(cmAssessEntity);
                } else {
                    id = cmAssessDao.save(cmAssessEntity);
                }

                final String city = cmAssessEntity.getCity();
                final String userId = cmAssessEntity.getUserId();
                final String deviceId = cmAssessEntity.getDeviceId();
                final String blockId = cmAssessEntity.getBlockId();

                deleteAssessCache(city, userId, deviceId, blockId);
                calculateResult.put("assessId", id);
            }

            calculateResult.put("averprice", cmAssessEntity.getUnitPrice());
            calculateResult.put("price", cmAssessEntity.getTotalPrice());

            jsonObject.put("data", calculateResult);
            jsonObject.put("result", ReturnAppResult.APP_SUCCESS.getResultCode());
            jsonObject.put("msg", ReturnAppResult.APP_SUCCESS.getResultMessage());

        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            jsonObject.put("result", ReturnAppResult.APP_FAIL.getResultCode());
            jsonObject.put("msg", ReturnAppResult.APP_FAIL.getResultMessage());
        }
        return jsonObject.toString();
    }

    /**
     * 评估结果页
     *
     * @param paramMap json格式
     * @return
     */
    @Override
    public Object assessResult(Map<String, Object> paramMap) {
        JSONObject jsonObject = JsonUtil.getExecuteOKJson();
        String cacheKey = "";
        try {
            String city = paramMap.get("city") == null ? "" : ((String[]) paramMap.get("city"))[0];
            String blockid = paramMap.get("blockId") == null ? "" : ((String[]) paramMap.get("blockId"))[0];
            String userId = paramMap.get("userId") == null ? "" : ((String) paramMap.get("userId"));
            String deviceid = paramMap.get("deviceId") == null ? "" : ((String) paramMap.get("deviceId"));
            String v = paramMap.get("v") == null ? null : ((String[]) paramMap.get("v"))[0];

            if (Strings.isNullOrEmpty(city) || Strings.isNullOrEmpty(blockid)) {
                throw new IllegalServiceParameterException("请完善搜索条件");
            }

            cacheKey = "getAssessResult_" + city + "_" + (Strings.isNullOrEmpty(
                    userId) ? deviceid : userId) + "_" + blockid + "_cache";

            RedisUtilsInterface redisUtils = (RedisUtilsInterface) SpringContextUtil.getBean("redisUtils");
            if (!Strings.isNullOrEmpty(cacheKey) && redisUtils.getValByKeyNew(
                    cacheKey) != null && !Strings.isNullOrEmpty(
                    redisUtils.getValByKeyNew(cacheKey)) && !"null".equalsIgnoreCase(
                    redisUtils.getValByKeyNew(cacheKey))) {
                return redisUtils.getValByKeyNew(cacheKey).trim();
            }

            String month = getTwoYearsAgoMonth();

            JSONObject result = new JSONObject();

            //取前2年价格趋势和当前价格
            JSONArray blockPrices = DataCenterAssessUtil.getBlockPrice(city, month, blockid, "24");
            result.put("priceList", blockPrices);

            String currentPrice = "";
            String currentHB = "";
            if (blockPrices != null && !blockPrices.isEmpty()) {
                JSONObject priceObj = (JSONObject) blockPrices.get(blockPrices.size() - 1);
                currentPrice = priceObj.get("price") == null ? "" : String.valueOf(priceObj.get("price"));
                currentHB = priceObj.get("hb") == null ? "" : String.valueOf(priceObj.get("hb"));
            }
            result.put("currentprice", currentPrice);
            result.put("currentHB", currentHB);

            //二手房列表信息
            JSONObject blockSell = DataCenterAssessUtil.getBlockSell(city, blockid, 2);
            String sellTotal = blockSell.get("total") == null ? "" : String.valueOf(blockSell.get("total"));
            result.put("sellTotal", sellTotal);
            result.put("sellList", blockSell.get("sell"));

            //租房信息列表
            JSONObject blockRent = DataCenterAssessUtil.getBlockRent(city, blockid, 1);
            String rentTotal = blockRent.get("total") == null ? "" : String.valueOf(blockRent.get("total"));
            result.put("rentTotal", rentTotal);
            result.put("rentList", blockRent.get("rent"));

            String lastMonth = DateUtils.getLastMonthStr(); // 获取上月份字串【yyyyMM】

            //小区评估列表
            List assessList = getAssessListNew("1", "5", "", city, blockid, "", true);
            JSONArray jsonList = warpAssessInfo(city, lastMonth, assessList);
            result.put("blockList", jsonList);

            //我的评估记录
            //618版本后改为数组
            if (!Strings.isNullOrEmpty(userId) || !Strings.isNullOrEmpty(deviceid)) {
                if (CmCommonUtils.versionCheck(v, version)) {
                    List myAssessList = getAssessListNew("1", "3", userId, city, "", deviceid, false);

                    if (CollectionUtils.isEmpty(myAssessList)) {
                        result.put("myAssess", new JSONArray());
                    } else {
                        JSONArray list = warpAssessInfo(city, lastMonth, myAssessList);
                        result.put("myAssess", list);
                    }

                } else {
                    List myAssessList = getAssessListNew("1", "1", userId, city, "", deviceid, false);
                    if (myAssessList != null && !myAssessList.isEmpty()) {
                        JSONArray list = warpAssessInfo(city, lastMonth, myAssessList);
                        result.put("myAssess", list.get(0));
                    } else {
                        result.put("myAssess", "{}");
                    }
                }
            } else {
                if (CmCommonUtils.versionCheck(v, version)) {
                    result.put("myAssess", new JSONArray());
                } else {
                    result.put("myAssess", "{}");
                }
            }

            jsonObject.put("data", result);
            jsonObject.put("result", ReturnAppResult.APP_SUCCESS.getResultCode());
            jsonObject.put("msg", ReturnAppResult.APP_SUCCESS.getResultMessage());

        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            jsonObject.put("result", ReturnAppResult.APP_FAIL.getResultCode());
            jsonObject.put("msg", ReturnAppResult.APP_FAIL.getResultMessage());
        }

        redisUtils.setValueExpireNew(cacheKey, jsonObject.toString(), 5, TimeUnit.MINUTES);
        return jsonObject.toString();
    }


    /**
     * 保存对评估的评分记录
     *
     * @param paramMap 参数
     * @return 执行结果
     * @throws ServiceRunException
     */
    @Override
    public Object saveAssessScore(Map<String, Object> paramMap) {
        Map<String, Object> response = new HashMap<>();
        try {
            CmAssessScoreEntity cmAssessScoreEntity = new CmAssessScoreEntity();
            paramMap.put("createTime", new Date());
            cmAssessScoreEntity = checkInterfaceParameter(paramMap, cmAssessScoreEntity);
            CmAssessEntity cmAssessEntity = cmAssessDao.getById(cmAssessScoreEntity.getAssessId());
            if (cmAssessEntity == null) {
                throw new Exception("接口调用异常或评估记录不存在");
            }

            cmAssessScoreDao.save(cmAssessScoreEntity);
            response.put("result", ReturnAppResult.APP_SUCCESS.getResultCode());
            response.put("msg", "成功");

        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            response.put("result", ReturnAppResult.APP_FAIL.getResultCode());
            response.put("msg", ReturnAppResult.APP_FAIL.getResultMessage());
        }

        return JSONObject.fromObject(response).toString();
    }

    @Override
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    public Object deleteAssess(Map<String, Object> paramMap) {
        Map<String, Object> response = new HashMap<>();
        try {
            if (paramMap.containsKey("id") && paramMap.get("id") != null) {
                String id = ((String[]) paramMap.get("id"))[0];
                if (Strings.isNullOrEmpty(id) || !StringUtils.isNumeric(id)) {
                    throw new Exception("接口调用异常或评估记录不存在");
                }

                Integer assessId = Integer.valueOf(((String[]) paramMap.get("id"))[0]);

                CmAssessEntity cmAssessEntity = cmAssessDao.getById(assessId);
                if (cmAssessEntity == null) {
                    throw new Exception("接口调用异常或评估记录不存在");
                }

                cmAssessEntity.setStatus("0");
                cmAssessDao.update(cmAssessEntity);

                deleteAssessCache(cmAssessEntity.getCity(), cmAssessEntity.getUserId(), cmAssessEntity.getDeviceId(),
                        cmAssessEntity.getBlockId());
            } else {
                throw new Exception("接口调用异常或评估记录不存在");
            }

            response.put("result", ReturnAppResult.APP_SUCCESS.getResultCode());
            response.put("msg", "成功");

        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            response.put("result", ReturnAppResult.APP_FAIL.getResultCode());
            response.put("msg", ReturnAppResult.APP_FAIL.getResultMessage());
        }

        return JSONObject.fromObject(response).toString();
    }

    /**
     * 获取评估列表
     *
     * @param paramMap 参数
     * @return 执行结果
     * @throws ServiceRunException
     */
    @Override
    public Object getAssess(Map<String, Object> paramMap) throws ServiceRunException {
        Map<String, Object> response = new HashMap<>();
        String userId = paramMap.get("userId") == null ? "" : ((String) paramMap.get("userId"));
        String city = paramMap.get("city") == null ? "" : ((String[]) paramMap.get("city"))[0];
        String blockId = paramMap.get("blockId") == null ? "" : ((String[]) paramMap.get("blockId"))[0];
        String deviceid = paramMap.get("deviceId") == null ? "" : ((String) paramMap.get("deviceId"));
        String currentPage = paramMap.get(CmConstant.PAGE) == null ? "" : ((String[]) paramMap.get(CmConstant.PAGE))[0];
        String pageSize = paramMap.get(CmConstant.PAGESIZE) == null ? "20" : ((String[]) paramMap.get(
                CmConstant.PAGESIZE))[0];

        pageSize = Strings.isNullOrEmpty(pageSize) ? "20" : pageSize;

        //        final String cacheKey = "getAssess_" + city + "_" + (Strings.isNullOrEmpty(
        //            userId) ? deviceid : userId) + "_" + blockId + currentPage + pageSize + "_cache";

        try {

            if (!CmCommonUtils.isNumeric(currentPage) || !CmCommonUtils.isNumeric(pageSize)) {
                throw new Exception("分页参数必须为数字!");
            }

            //            RedisUtilsInterface redisUtils = (RedisUtilsInterface) SpringContextUtil.getBean("redisUtils");
            //            if (!Strings.isNullOrEmpty(cacheKey.toString()) && redisUtils.getValByKeyNew(
            //                cacheKey.toString()) != null && !Strings.isNullOrEmpty(
            //                redisUtils.getValByKeyNew(cacheKey.toString())) && !"null".equalsIgnoreCase(
            //                redisUtils.getValByKeyNew(cacheKey.toString()))) {
            //                return redisUtils.getValByKeyNew(cacheKey.toString()).trim();
            //            }

            Page page = new Page();
            if (!Strings.isNullOrEmpty(currentPage)) {
                page.setCurrentPage(Integer.valueOf(currentPage));
            }

            if (!Strings.isNullOrEmpty(pageSize)) {
                page.setPageSize(Integer.valueOf(pageSize));
            }

            // 查询参数 如果userId不为空，按userId查，userId为空deviceId不为空按deviceId查询
            Map<String, Object> param = new HashMap<>();
            if (!Strings.isNullOrEmpty(userId)) {
                param.put("EQ_userId", userId);
            } else if (!Strings.isNullOrEmpty(deviceid)) {
                param.put("EQ_deviceId", deviceid);
            }

            if (!Strings.isNullOrEmpty(city)) {
                param.put("EQ_city", city);
            }
            if (!Strings.isNullOrEmpty(blockId)) {
                param.put("EQ_blockId", blockId);
            }
            param.put("EQ_status", "1");

            QueryParams<CmAssessEntity> queryParam = new QueryParams<>();
            queryParam.setPaging(page);
            queryParam.setSearchParams(param);
            List<CmAssessEntity> cmAssessEntityList = cmAssessDao.queryByPage(queryParam);

            //6.1.8 需求变更 添加小区上月均价和环比
            JSONArray list = new JSONArray();
            if (cmAssessEntityList != null && !cmAssessEntityList.isEmpty()) {
                String lastMonth = DateUtils.getLastMonthStr(); // 获取上月份字串【yyyyMM】
                unwarpAssess(cmAssessEntityList);
                list = JSONArray.fromObject(cmAssessEntityList);
                for (Object assess : list) {
                    JSONObject jsonNode = (JSONObject) assess;
                    if (jsonNode.get("city") != null && jsonNode.get("blockId") != null) {
                        JSONArray blockPrices = DataCenterAssessUtil.getBlockPrice(city, lastMonth, String.valueOf(
                                jsonNode.get("blockId")), "1");
                        if (!blockPrices.isEmpty()) {
                            JSONObject blockNode = (JSONObject) blockPrices.get(0);
                            jsonNode.put("lastMonthPrice", blockNode.get("price"));
                            jsonNode.put("hb", blockNode.get("hb"));
                        }
                    }
                }
            }
            Map<String, Object> listMap = new HashMap<>();
            listMap.put("list", list);
            listMap.put("total", queryParam.getPaging().getRecords());
            listMap.put("currentPage", currentPage);
            listMap.put("pageSize", pageSize);

            response.put("data", listMap);
            response.put("result", ReturnAppResult.APP_SUCCESS.getResultCode());
            response.put("msg", "成功");
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            response.put("result", ReturnAppResult.APP_FAIL.getResultCode());
            response.put("msg", ReturnAppResult.APP_FAIL.getResultMessage());
        }

        JSONObject resultJSON = JSONObject.fromObject(response);
        //        redisUtils.setValueExpireNew(cacheKey, resultJSON.toString(), 1, TimeUnit.MINUTES);
        return resultJSON.toString();
    }

    private void unwarpAssess(List<CmAssessEntity> cmAssessEntityList) {
        for (CmAssessEntity cmAssessEntity : cmAssessEntityList) {
            cmAssessEntity.setAssessDate(DateUtils.parseDate(cmAssessEntity.getCreateTime(), "MM-dd"));
            cmAssessEntity.setTimestamp(DateUtils.parseDate(cmAssessEntity.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
            cmAssessEntity.setTotalPrice(cmAssessEntity.getTotalPrice().setScale(0, BigDecimal.ROUND_HALF_UP));
            cmAssessEntity.setUnitPrice(cmAssessEntity.getUnitPrice().setScale(0, BigDecimal.ROUND_HALF_UP));
            cmAssessEntity.setCreateTime(null);
        }
    }

    /**
     * 首页数据接口
     *
     * @param map 城市 用户信息
     * @return
     */
    @Override
    public Object queryAssessHome(Map<String, Object> map) {
        String city = map.get("city") == null ? null : ((String[]) map.get("city"))[0];
        String userId = map.get("userId") == null ? null : ((String) map.get("userId"));
        String deviceId = map.get("deviceId") == null ? null : ((String) map.get("deviceId"));
//        String userId = map.get("userId") == null ? null : ((String[]) map.get("userId"))[0];
//        String deviceId = map.get("deviceId") == null ? null : ((String[]) map.get("deviceId"))[0];
        String v = map.get("v") == null ? "" : ((String[]) map.get("v"))[0];

        final String cityPriceMonthNum = "1"; // 需要统计的月份总数
        // 验证入参合法性
        if (StringUtils.isBlank(city) || (StringUtils.isNotBlank(userId) && !NumberUtils.isNumber(userId))) {
            return JsonUtil.getParamErrorJson();
        }

        JSONObject mergedJSON = new JSONObject();
        final String lastMonth = DateUtils.getLastMonthStr(); // 获取上月份字串【yyyyMM】
        final String curMonth = DateUtils.getCurMonthStr();
        final String cacheKey = "getAssessHome_" + city + "_" + (Strings.isNullOrEmpty(
                userId) ? deviceId : userId) + "_cache";

        try {
            RedisUtilsInterface redisUtils = (RedisUtilsInterface) SpringContextUtil.getBean("redisUtils");
            if (!Strings.isNullOrEmpty(cacheKey) && redisUtils.getValByKeyNew(
                    cacheKey) != null && !Strings.isNullOrEmpty(redisUtils.getValByKeyNew(cacheKey)) && !"null".equalsIgnoreCase(redisUtils.getValByKeyNew(cacheKey))) {
                return redisUtils.getValByKeyNew(cacheKey).trim();
            }

            JSONObject empty = new JSONObject();

            // part 1.当前城市上月均价、环比数据
            JSONArray cityPriceArray = DataCenterAssessUtil.getCityPrice(city, lastMonth, cityPriceMonthNum);
            mergedJSON.put("latestPrice", CollectionUtils.isEmpty(cityPriceArray) ? empty : cityPriceArray.get(0));

            // part 1.当前城市本月均价、环比数据
            JSONArray curCityPriceArray = DataCenterAssessUtil.getCityPrice(city, curMonth, cityPriceMonthNum);
            mergedJSON.put("currentCityPrice",
                    CollectionUtils.isEmpty(curCityPriceArray) ? empty : curCityPriceArray.get(0));

            // part 2.当前城市所有区域的均价、环比数据
            JSONArray districtPriceList = DataCenterAssessUtil.getAllDistrictPrice(city, lastMonth);
            // 匹配房价地图接口,增加当前均价,在售套数
            JSONArray currentMonthDistrictList = DataCenterAssessUtil.getAllDistrictPriceDetail(city);
            // 房源少于1000套
            JSONArray lessHouseList = new JSONArray();

            for (Object district : districtPriceList) {
                JSONObject districtNode = (JSONObject) district;
                districtNode.put("month", lastMonth);
                for (Object cdistrict : currentMonthDistrictList) {
                    JSONObject cdistrictNode = (JSONObject) cdistrict;
                    if (districtNode.get("district") != null && cdistrictNode.get("district") != null) {
                        if (districtNode.get("district").toString().equalsIgnoreCase(
                                cdistrictNode.get("district").toString())) {
                            districtNode.put("house_num", cdistrictNode.get("house_num"));
                            districtNode.put("x", cdistrictNode.get("x"));
                            districtNode.put("y", cdistrictNode.get("y"));
                            districtNode.put("hb", cdistrictNode.get("hb"));
                            districtNode.put("current_price", cdistrictNode.get("price"));
                        }
                    }
                }
            }

            Iterator<JSONObject> listIterator = districtPriceList.iterator();
            while (listIterator.hasNext()) {
                JSONObject cdistrictNode = listIterator.next();
                if (cdistrictNode.get("house_num") != null && StringUtils.isNumeric(
                        cdistrictNode.get("house_num").toString()) && Integer.parseInt(
                        cdistrictNode.get("house_num").toString()) < 1000) {
                    lessHouseList.add(cdistrictNode);
                    listIterator.remove();
                }
            }

            mergedJSON.put("districtPriceList", districtPriceList);
            mergedJSON.put("lessHouseDistrictList", lessHouseList);

            // part 3.当前用户的最近一条评估记录
            if (StringUtils.isEmpty(userId) && StringUtils.isEmpty(deviceId)) { // userId 和 deviceId 同时为空，则不查询我的评估记录
                mergedJSON.put("assessDetail", new JSONArray());
            } else {
                //618版本后改为数组
                if (CmCommonUtils.versionCheck(v, version)) {
                    List myAssessList = getAssessList("1", "3", userId, city, "", deviceId, false);
                    if (CollectionUtils.isEmpty(myAssessList)) {
                        mergedJSON.put("assessDetail", new JSONArray());
                    } else {
                        JSONArray list = warpAssessInfo(city, lastMonth, myAssessList);

                        mergedJSON.put("assessDetail", list);
                    }
                } else {
                    List myAssessList = getAssessList("1", "1", userId, city, "", deviceId, false);
                    if (CollectionUtils.isEmpty(myAssessList)) {
                        mergedJSON.put("assessDetail", empty);
                    } else {

                        //6.1.8 需求变更 添加小区上月均价和环比
                        JSONArray list = warpAssessInfo(city, lastMonth, myAssessList);

                        mergedJSON.put("assessDetail", list.get(0));
                    }
                }

            }
        } catch (IllegalServiceParameterException e) {
            LOGGER.error(e.getMessage());
        }
        JSONObject resultJSON = JsonUtil.getExecuteOKJson(mergedJSON);

        redisUtils.setValueExpireNew(cacheKey, resultJSON.toString(), 1, TimeUnit.MINUTES);
        return resultJSON.toString();
    }

    private JSONArray warpAssessInfo(String city, String lastMonth, List myAssessList) throws IllegalServiceParameterException {
        //6.1.8 需求变更 添加小区上月均价和环比
        JSONArray list = JSONArray.fromObject(myAssessList);
        for (Object assess : list) {
            JSONObject jsonNode = (JSONObject) assess;
            if (jsonNode.get("city") != null && jsonNode.get("blockId") != null) {
                JSONArray blockPrices = DataCenterAssessUtil.getBlockPrice(city, lastMonth,
                        String.valueOf(jsonNode.get("blockId")),
                        "1");
                if (!blockPrices.isEmpty()) {
                    JSONObject blockNode = (JSONObject) blockPrices.get(0);
                    jsonNode.put("lastMonthPrice", blockNode.get("price"));
                    jsonNode.put("hb", blockNode.get("hb"));
                }
            }
        }
        return list;
    }

    @Override
    public Object queryAssessableBlocks(Map<String, Object> map) {
        String city = map.get("city") == null ? null : ((String[]) map.get("city"))[0];
        String keyword = map.get("keyword") == null ? null : ((String[]) map.get("keyword"))[0];
        // 验证入参合法性
        if (StringUtils.isBlank(city) || StringUtils.isBlank(keyword)) {
            return JsonUtil.getParamErrorJson();
        }
        final int MAX_NUM = 10; // 返回给客户端的最大数据量（关键词如“花”、“城”时，数据量很大，不宜全部返回）
        JSONObject mergedJSON = new JSONObject();
        try {
            // part 1.根据城市名、关键词，获取可估价的二手房小区列表
            JSONArray blockPriceArray = DataCenterAssessUtil.getBlockListForCalculate(city, keyword);
            if (CollectionUtils.isNotEmpty(blockPriceArray) && blockPriceArray.size() > MAX_NUM) {
                List subList = blockPriceArray.subList(0, MAX_NUM);
                blockPriceArray = JSONArray.fromObject(subList);
            }
            mergedJSON.put("blockList", CollectionUtils.isEmpty(blockPriceArray) ? new JSONArray() : blockPriceArray);
        } catch (IllegalServiceParameterException e) {
            LOGGER.error(e.getMessage());
        } catch (UnsupportedEncodingException e) {
            LOGGER.error(e.getMessage());
        } catch (Exception e) {
            LOGGER.error(e.getMessage());
        }
        JSONObject resultJSON = JsonUtil.getExecuteOKJson(mergedJSON);
        return resultJSON.toString();
    }

    @Override
    public Object queryDistrictTrend(Map<String, Object> map) {
        String city = map.get("city") == null ? null : ((String[]) map.get("city"))[0];
        String district = map.get("district") == null ? null : ((String[]) map.get("district"))[0];
        // 验证入参合法性
        if (StringUtils.isBlank(city) || StringUtils.isBlank(district)) {
            return JsonUtil.getParamErrorJson();
        }
        final int currentMonthNum = 1;  // 当前月份只取一条
        final int historyMonthNum = 24; // 数据中心接口参数，自month起向后共取几个月
        JSONObject mergedJSON = new JSONObject();
        JSONObject resultJSON = new JSONObject();
        String curMonth = DateUtils.getCurMonthStr();   // 获取本月月份字串【yyyyMM】
        String lastMonth = DateUtils.getLastMonthStr(); // 获取上个月的月份字串【yyyyMM】
        String historyMonth = DateUtils.dateToString(DateUtils.getMagicMonth(-DateUtils.ONE_YEAR_MONTHS * 2),
                DateUtils.YEARMONTH);
        try {
            //			district = new String(district.getBytes("iso8859-1"), "utf-8");
            // part 1.根据城市名、区域、月份，获取该区域的当前月份均价、环比数据
            JSONArray districtArray = DataCenterAssessUtil.getDistrictPrice(city, lastMonth, district,
                    String.valueOf(currentMonthNum));
            if (CollectionUtils.isEmpty(districtArray)) {
                mergedJSON.put("currentDistrictPrice", StringUtils.DEFAULT_EMPTY_STRING);
                mergedJSON.put("currentDistrictHB", StringUtils.DEFAULT_EMPTY_STRING);
            } else {
                mergedJSON.put("currentDistrictPrice", districtArray.getJSONObject(0).get("price"));
                mergedJSON.put("currentDistrictHB", districtArray.getJSONObject(0).get("hb"));
            }
            // part 2.根据城市名、区域、月份，获取该区域的历史月份均价、环比数据
            JSONArray districtHistoryArray = DataCenterAssessUtil.getDistrictPrice(city, historyMonth, district,
                    String.valueOf(historyMonthNum));
            mergedJSON.put("districtPriceList", districtHistoryArray);

            // part 3.当前城市二手房月均价、环比数据
            JSONArray cityPriceArray = DataCenterAssessUtil.getCityPrice(city, historyMonth,
                    String.valueOf(historyMonthNum));
            mergedJSON.put("cityPriceList", cityPriceArray);

            // part 4.根据城市名、区域、月份，获取该区域中所有版块的均价、环比数据
            JSONArray streetArray = DataCenterAssessUtil.getDistrictAllStreetPrice(city, lastMonth, district);
            mergedJSON.put("streetList", streetArray);

            final int topNum = 5; // 小区均价涨跌榜前几条
            // part 5.根据城市名、区域、数量n，获取该区域所有小区中环比上涨前n名
            JSONArray incrBlockArray = DataCenterAssessUtil.getDistrictITop(city, district, lastMonth, topNum);
            mergedJSON.put("blockIyncList", incrBlockArray);

            // part 6.根据城市名、区域、数量n，获取该区域所有小区中环比下跌前n名
            JSONArray decrBlockArray = DataCenterAssessUtil.getDistrictDTop(city, district, lastMonth, topNum);
            mergedJSON.put("blockDyncList", decrBlockArray);
            resultJSON = JsonUtil.getExecuteOKJson(mergedJSON);
        } catch (UnsupportedEncodingException e) {
            LOGGER.error(e.getMessage());
        } catch (IllegalServiceParameterException e) {
            LOGGER.error(e.getMessage());
        } catch (Exception e) {
            LOGGER.error(e.getMessage());
        }
        return resultJSON.toString();
    }

    /**
     * 板块street走势页
     *
     * @param paramMap 板块street走势页 参数
     * @return 结果
     * @throws ServiceRunException
     */
    @Override
    public Object streetTrend(Map<String, Object> paramMap) throws ServiceRunException {
        JSONObject jsonObject = JsonUtil.getExecuteOKJson();
        try {
            String district = paramMap.get("district") == null ? "" : ((String[]) paramMap.get("district"))[0];
            String city = paramMap.get("city") == null ? "" : ((String[]) paramMap.get("city"))[0];
            String streetId = paramMap.get("streetid") == null ? "" : ((String[]) paramMap.get("streetid"))[0];

            if (Strings.isNullOrEmpty(city) || Strings.isNullOrEmpty(district) || Strings.isNullOrEmpty(streetId)) {
                throw new Exception("请完善搜索条件");
            }
            JSONObject data = new JSONObject();
            String month = getTwoYearsAgoMonth();
            //街道价格列表 当前价格
            JSONArray streetPrices = DataCenterAssessUtil.getStreetPrice(city, month, streetId, "24");
            data.put("streetPriceList", streetPrices);
            if (streetPrices != null && !streetPrices.isEmpty()) {
                JSONObject streetPrice = (JSONObject) streetPrices.get(streetPrices.size() - 1);
                data.put("currentStreetPrice", streetPrice.get("price"));
                data.put("currentStreetHB", streetPrice.get("hb"));
            }
            //区域价格列表
            JSONArray districtPrices = DataCenterAssessUtil.getDistrictPrice(city, month, district, "24");
            data.put("districtPriceList", districtPrices);

            JSONObject streetResult = DataCenterAssessUtil.getStreetTop(city, streetId, month, "10");
            if (streetResult != null && streetResult.get("topBlockData") != null) {
                JSONObject topBlockData = (JSONObject) streetResult.get("topBlockData");
                JSONArray riceTop = (JSONArray) topBlockData.get("riseTop");
                JSONArray downTop = (JSONArray) topBlockData.get("dropTop");

                data.put("blockDyncList", downTop);
                data.put("blockIyncList", riceTop);
            }

            jsonObject.put("data", data);
            jsonObject.put("result", ReturnAppResult.APP_SUCCESS.getResultCode());
            jsonObject.put("msg", "成功");
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            jsonObject.put("result", ReturnAppResult.APP_FAIL.getResultCode());
            jsonObject.put("msg", ReturnAppResult.APP_FAIL.getResultMessage());
        }

        return jsonObject.toString();
    }

    /**
     * 搜索关键词匹配的小区名称、ID、所属板块名称、上月均价、环比
     *
     * @param paramMap
     * @return
     * @throws ServiceRunException
     */
    @Override
    public Object getBlockByKeyword(Map<String, Object> paramMap) throws ServiceRunException {
        JSONObject jsonObject = JsonUtil.getExecuteOKJson();
        try {
            String city = paramMap.get("city") == null ? "" : ((String[]) paramMap.get("city"))[0];
            String keyword = paramMap.get("keyword") == null ? "" : ((String[]) paramMap.get("keyword"))[0];

            if (Strings.isNullOrEmpty(city) || Strings.isNullOrEmpty(keyword)) {
                throw new Exception("请完善搜索条件");
            }

            JSONObject data = new JSONObject();
            //小区列表
            JSONArray streetPrices = DataCenterAssessUtil.getBlockByKeyword(city, keyword);
            data.put("blockList", streetPrices);

            jsonObject.put("data", data);
            jsonObject.put("result", ReturnAppResult.APP_SUCCESS.getResultCode());
            jsonObject.put("msg", "成功");
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            jsonObject.put("result", ReturnAppResult.APP_FAIL.getResultCode());
            jsonObject.put("msg", ReturnAppResult.APP_FAIL.getResultMessage());
        }

        return jsonObject.toString();
    }

    /**
     * 五、	周边房价搜索
     *
     * @param paramMap 地图坐标与范围
     * @return 坐标范围内小区的坐标、名称、价格、环比数据
     * @throws ServiceRunException
     */
    @Override
    public Object   getBlockByDistance(Map<String, Object> paramMap) throws ServiceRunException {
        JSONObject jsonObject = JsonUtil.getExecuteOKJson();
        try {
            String city = paramMap.get("city") == null ? "" : ((String[]) paramMap.get("city"))[0];
            String x = paramMap.get("x") == null ? "" : ((String[]) paramMap.get("x"))[0];
            String y = paramMap.get("y") == null ? "" : ((String[]) paramMap.get("y"))[0];
            String range = paramMap.get("range") == null ? "" : ((String[]) paramMap.get("range"))[0];
            String page = paramMap.get("page") == null ? "" : ((String[]) paramMap.get("page"))[0];
            String pageSize = paramMap.get("pagesize") == null ? "" : ((String[]) paramMap.get("pagesize"))[0];
            String order = paramMap.get("order") == null ? "" : ((String[]) paramMap.get("order"))[0];
            //TODO 新增类型
            String mapType = "0";
            try {
                LOGGER.info("mapType=" + mapType);
                mapType = paramMap.get("is_t_map") == null ? "" : ((String[]) paramMap.get("is_t_map"))[0];
            } catch (Exception e) {
                LOGGER.error(e.getMessage());
            }


            if (Strings.isNullOrEmpty(city) || Strings.isNullOrEmpty(x) || Strings.isNullOrEmpty(
                    y) || Strings.isNullOrEmpty(range)) {
                throw new Exception("assessResult : parameter is empty !!!");
            }

            if (!StringUtils.isDigit(x) || !StringUtils.isDigit(y) || !StringUtils.isDigit(range)) {
                throw new Exception("assessResult : parameter cant parse to number !!!");
            }

            JSONObject data = new JSONObject();

            JSONArray blockList = DataCenterAssessUtil.getBlockByDistance(city, Double.parseDouble(x),
                    Double.parseDouble(y),
                    Integer.parseInt(range),mapType);

            if ("hb".equals(order)) {
                //按环比降序排序
                Collections.sort(blockList, new Comparator<Map<String, String>>() {
                    public int compare(Map<String, String> o1, Map<String, String> o2) {
                        //取出操作时间
                        int ret;
                        try {
                            double d1 = Double.parseDouble(String.valueOf(o1.get("hb")));
                            double d2 = Double.parseDouble(String.valueOf(o2.get("hb")));

                            ret = Double.compare(d1, d2);

                            if (ret != 0) {
                                ret = -ret;
                            }
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                        return ret;
                    }
                });
            }

            List list;
            if (!Strings.isNullOrEmpty(page) && !Strings.isNullOrEmpty(pageSize) && StringUtils.isNumeric(
                    page) && StringUtils.isNumeric(pageSize)) {
                int begin = (Integer.parseInt(page) - 1) * Integer.parseInt(pageSize);
                if (begin >= blockList.size()) {
                    begin = blockList.size() - Integer.parseInt(pageSize);
                }
                int end = begin + Integer.parseInt(pageSize);
                list = blockList.subList(begin < 0 ? 0 : begin, end > blockList.size() ? blockList.size() : end);
            } else {
                list = blockList;
            }

            data.put("blockList", list);

            jsonObject.put("data", data);
            jsonObject.put("result", ReturnAppResult.APP_SUCCESS.getResultCode());
            jsonObject.put("msg", "成功");
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            jsonObject.put("result", ReturnAppResult.APP_FAIL.getResultCode());
            jsonObject.put("msg", ReturnAppResult.APP_FAIL.getResultMessage() + ":" + e.getMessage());
        }

        return jsonObject.toString();
    }

    /**
     * 房价地图接口
     *
     * @param paramMap 城市编码
     * @return 区域信息 district——区属 month——月份 price——均价 hb——环比 x——经度 y——纬度
     * @throws ServiceRunException
     */
    @Override
    public Object getDistrictForMap(Map<String, Object> paramMap) throws ServiceRunException {
        JSONObject jsonObject = JsonUtil.getExecuteOKJson();
        try {
            String city = paramMap.get("city") == null ? "" : ((String[]) paramMap.get("city"))[0];
            String district = paramMap.get("district") == null ? "" : ((String[]) paramMap.get("district"))[0];

            if (Strings.isNullOrEmpty(city)) {
                throw new Exception("city不能为空!");
            }

            JSONObject data = new JSONObject();

            JSONArray blockList = DataCenterAssessUtil.getAllDistrictPriceDetail(city);

            final String curMonth = DateUtils.getCurMonthStr();
            JSONObject empty = new JSONObject();
            // part 1.当前城市本月均价、环比数据
            JSONArray curCityPriceArray = DataCenterAssessUtil.getCityPrice(city, curMonth, "1");

            if (!Strings.isNullOrEmpty(district)) {
                JSONObject districtInfo = null;
                for (Object object : blockList) {
                    if (district.equals(((JSONObject) object).get("district"))) {
                        districtInfo = (JSONObject) object;
                        setShortNum(districtInfo);
                        break;
                    }
                }

                data.put("district", districtInfo);
            } else {
                for (Object object : blockList) {
                    JSONObject districtInfo = (JSONObject) object;
                    setShortNum(districtInfo);
                }

                data.put("districtList", blockList);

                if (!CollectionUtils.isEmpty(curCityPriceArray)) {
                    JSONObject districtInfo = (JSONObject) curCityPriceArray.get(0);
                    setShortNum(districtInfo);
                    data.put("currentCityPrice", districtInfo);
                } else {
                    data.put("currentCityPrice", empty);
                }
            }
            //拼接新房接口信息
//            List<NameValuePair> queryParams = new ArrayList<>();
//            queryParams.add(new BasicNameValuePair("method", "getAppIndexGroupData"));
//            queryParams.add(new BasicNameValuePair("city", city));
//            //设置超时时间，防止时间太长导致dubbo超时和请求堆积
//            String jsonStr = HttpClientUtil.doGet(newHouseUrl, queryParams, 2000, null);
//            LOGGER.debug("jsonStr=[{}]", jsonStr);
//            JSONObject newHouseResult = JSONObject.fromObject(jsonStr);
//            if (newHouseResult != null) {
//                if ("200".equals(newHouseResult.get("code").toString())) {
//                    data.put("estateInfo", newHouseResult.get("data"));
//                }
//            }
            jsonObject.put("data", data);
            jsonObject.put("result", ReturnAppResult.APP_SUCCESS.getResultCode());
            jsonObject.put("msg", "成功");
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            jsonObject.put("result", ReturnAppResult.APP_FAIL.getResultCode());
            jsonObject.put("msg", ReturnAppResult.APP_FAIL.getResultMessage() + ":" + e.getMessage());
        }

        return jsonObject.toString();
    }

    /**
     * 缩略显示首页房源套数,大于等于6位数的优化显示,101000=10.1万,100000=10万
     *
     * @param districtInfo 区块信息
     */
    private String setShortNum(JSONObject districtInfo) {
        String houseNumStr = "";
        if (districtInfo.containsKey("house_num") && StringUtils.isNumeric(
                String.valueOf(districtInfo.get("house_num")))) {
            houseNumStr = String.valueOf(districtInfo.get("house_num"));
            BigDecimal houseNum = new BigDecimal(houseNumStr);
            if (houseNum.compareTo(new BigDecimal(100000)) >= 0) {
                houseNumStr = String.valueOf(houseNum.divide(new BigDecimal(10000), 1, BigDecimal.ROUND_HALF_UP));
                if ("0".equals(houseNumStr.substring(houseNumStr.indexOf(".") + 1, houseNumStr.length()))) {
                    houseNumStr = houseNumStr.substring(0, houseNumStr.indexOf("."));
                }

                //不方便判断是否首页调用,加一个返回字段
                districtInfo.put("house_num_short", houseNumStr);
                districtInfo.put("house_num_unit", "万");
            } else {
                districtInfo.put("house_num_short", houseNumStr);
                districtInfo.put("house_num_unit", "");
            }
        }
        return houseNumStr;
    }


    private void deleteAssessCache(String city, String userId, String deviceId, String blockId) {
        final String cacheKey = "getAssessResult_" + city + "_" + (Strings.isNullOrEmpty(
                userId) ? deviceId : userId) + "_" + blockId + "_cache";

        final String cacheKey1 = "getAssessHome_" + city + "_" + (Strings.isNullOrEmpty(
                userId) ? deviceId : userId) + "_cache";

        redisUtils.deleteByKeyNew(cacheKey);
        redisUtils.deleteByKeyNew(cacheKey1);
    }

    /**
     * 获取评估记录列表
     *
     * @param currentPage 当前页
     * @param pageSize    页码
     * @param userId      用户ID
     * @param city        城市ID
     * @param blockId     小区ID
     * @param deviceId    设备标识
     * @param noQuick     不展示快速评估记录
     * @return 列表
     */
    private List getAssessList(
            String currentPage, String pageSize, String userId, String city, String blockId, String deviceId,
            boolean noQuick
    ) {
        QueryParams<CmAssessEntity> queryParam = getCmAssessEntityQueryParams(currentPage, pageSize, userId, city,
                blockId, deviceId, noQuick);
        List<CmAssessEntity> cmAssessEntityList = cmAssessDao.queryByPage(queryParam);

        unwarpAssess(cmAssessEntityList);

        return cmAssessEntityList;
    }

    /**
     * assessresult 分页count效率较低，直接limit查询
     *
     * @param currentPage
     * @param pageSize
     * @param userId
     * @param city
     * @param blockId
     * @param deviceId
     * @param noQuick
     * @return
     */
    private List getAssessListNew(
            String currentPage, String pageSize, String userId, String city, String blockId, String deviceId,
            boolean noQuick
    ) {
        QueryParams<CmAssessEntity> queryParam = getCmAssessEntityQueryParams(currentPage, pageSize, userId, city,
                blockId, deviceId, noQuick);
        List<CmAssessEntity> cmAssessEntityList = cmAssessDao.limitQuery(queryParam);

        unwarpAssess(cmAssessEntityList);

        return cmAssessEntityList;
    }

    private QueryParams<CmAssessEntity> getCmAssessEntityQueryParams(
            String currentPage, String pageSize, String userId, String city, String blockId, String deviceId,
            boolean noQuick
    ) {
        Page page = new Page();
        if (!Strings.isNullOrEmpty(currentPage)) {
            page.setCurrentPage(Integer.valueOf(currentPage));
        }

        if (!Strings.isNullOrEmpty(pageSize)) {
            page.setPageSize(Integer.valueOf(pageSize));
        }

        // 查询参数
        Map<String, Object> param = new HashMap<>();
        if (!Strings.isNullOrEmpty(userId)) {
            param.put("EQ_userId", userId);
        } else if (!Strings.isNullOrEmpty(deviceId)) {
            param.put("EQ_deviceId", deviceId);
        }

        if (!Strings.isNullOrEmpty(city)) {
            param.put("EQ_city", city);
        }
        if (!Strings.isNullOrEmpty(blockId)) {
            param.put("EQ_blockId", blockId);
        }

        param.put("EQ_status", "1");
        if (noQuick) {
            //不展示快速评估记录
            param.put("EQ_noQuickSearch", "1");
        }

        QueryParams<CmAssessEntity> queryParam = new QueryParams<>();
        queryParam.setPaging(page);
        queryParam.setSearchParams(param);

        return queryParam;
    }

    protected <T> T checkInterfaceParameter(Map<String, Object> map, T object) throws IllegalServiceParameterException {
        BeanUtil.transMap2Bean2(map, object);
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();
        Set<ConstraintViolation<T>> constraintViolations = validator.validate(object);
        if (!constraintViolations.isEmpty() && constraintViolations.size() > 0) {
            StringBuilder error = new StringBuilder("entity invalidator !!! ");
            for (ConstraintViolation cv : constraintViolations) {
                error.append(cv.getPropertyPath()).append(":").append(cv.getMessage()).append("!");
            }
            throw new IllegalServiceParameterException(error.toString());
        }
        return object;
    }


    @Override
    public Object exectue(Parameter parameter) throws ServiceRunException {
        return null;
    }

    @Override
    public boolean isControlService() {
        return false;
    }

    @Override
    public boolean isLogService() {
        return false;
    }

    @Override
    public boolean isMonitorService() {
        return false;
    }

    @Override
    public Object rollback() {
        return null;
    }

    @Override
    public void commit() {

    }

    private static String getTwoYearsAgoMonth() {
        Calendar calendar = Calendar.getInstance();
        //当前月份不一定有数据，可能一个维度有，一个维度没有，所以取到上个月数据
        calendar.add(Calendar.MONTH, -24);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
        return sdf.format(calendar.getTime());
    }
}
