package com.goafanti.evaluation.controller;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.validation.Valid;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.goafanti.common.bo.Result;
import com.goafanti.common.constant.ErrorConstants;
import com.goafanti.common.controller.BaseApiController;
import com.goafanti.common.model.DistrictGlossory;
import com.goafanti.common.model.IndustryCategory;
import com.goafanti.common.model.ValueEvaluation;
import com.goafanti.common.service.DistrictGlossoryService;
import com.goafanti.common.service.IndustryCategoryService;
import com.goafanti.common.utils.LoggerUtils;
import com.goafanti.core.shiro.token.TokenManager;
import com.goafanti.evaluation.bo.ForecastIncome;
import com.goafanti.evaluation.bo.Step1;
import com.goafanti.evaluation.bo.Step2;
import com.goafanti.evaluation.bo.Step3;
import com.goafanti.evaluation.bo.Step4;
import com.goafanti.evaluation.bo.Step5;
import com.goafanti.evaluation.bo.Step6;
import com.goafanti.evaluation.bo.Step7;
import com.goafanti.evaluation.bo.YearIncome;
import com.goafanti.evaluation.enums.ProfitRate;
import com.goafanti.evaluation.service.ValueEvaluationService;

@RestController
@RequestMapping(value = "/api/user/evaluate")
public class UserEvaluationApiController extends BaseApiController {

	private static final String			GOVERNMENT_LOAN_ROR	= "government_loan_ror"; //政府贷款利率
	private static final Logger			logger				= LoggerFactory.getLogger(UserEvaluationApiController.class);
	private static final MathContext	DEFAULT_PRECISION	= new MathContext(4, RoundingMode.HALF_UP); //默认精度

	private static final String			STEP1				= "0";
	private static final String			STEP2				= "1";
	private static final String			STEP3				= "2";
	private static final String			STEP4				= "3";
	private static final String			STEP5				= "4";
	private static final String			STEP6				= "5";
	private static final String			STEP7				= "6";
	private static final Integer[]		SCORES				= new Integer[] { 100, 80, 60, 40, 20, 0 };
	private static final Integer[]		DISCOUNT_SCORES		= new Integer[] { 1, 2, 3, 4, 5 }; //折扣分数
	private static final BigDecimal		MIN_RATE			= new BigDecimal(2); //最小速率
	private static final BigDecimal		MAX_RATE			= new BigDecimal(6); //最大速率
	private static final BigDecimal		HUNDRED				= new BigDecimal(100);
	private static final BigDecimal		PERCENTAGE			= new BigDecimal(0.01, DEFAULT_PRECISION);//百分比

	@Autowired
	ValueEvaluationService				valueEvaluationService; //价值评估
	@Autowired
	private DistrictGlossoryService		districtGlossoryService; //地区词汇
	@Autowired
	private IndustryCategoryService		industryCategoryService; //行业分类

	/**
	 * 新增评估数据
	 * @return
	 */
	@RequestMapping(value = "/create", method = RequestMethod.GET)
	public Result create() {
		ValueEvaluation ve = new ValueEvaluation();
		ve.setUid(TokenManager.getUserId());
		ve.setStep(0);
		ve.setValue(0l);
		ve.setLog("{}");
		valueEvaluationService.insert(ve);
		return new Result(ve.getId().toString());
	}

	/**
	 * 通过用户id获得列表数据
	 * @param pageNo
	 * @param pageSize
	 * @return
	 */
	@RequestMapping(value = "/list", method = RequestMethod.GET)
	public Result list(String pageNo, String pageSize) {
		return new Result().data(valueEvaluationService.list(handlePageNo(pageNo), handlePageSize(pageSize)));
	}

	/**
	 * 根据用户和id获得评估信息
	 * @param id
	 * @return
	 */
	@RequestMapping(value = "/info/{id}", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
	public Result info(@PathVariable String id) {
		Assert.isTrue(StringUtils.isNumeric(id), ErrorConstants.EVALUATE_ID);
		ValueEvaluation ve = valueEvaluationService.getMyEvaluation(Long.valueOf(id));
		Assert.notNull(ve, ErrorConstants.EVALUATE_ID);
		Map<String, Object> res = new HashMap<>();
		res.put("name", ve.getName());
		res.put("step", ve.getStep());
		res.put("value", ve.getValue());
		res.put("steps", JSON.parse(ve.getLog()));
		return new Result().data(res);
	}

	/**
	 * 删除评估信息(可批量)
	 * @param ids
	 * @return
	 */
	@RequestMapping(value = "/remove", method = RequestMethod.POST)
	public Result remove(String ids) {
		Assert.isTrue(StringUtils.isNotBlank(ids), ErrorConstants.EVALUATE_PARAM);
		Result res = new Result();
		List<Long> idList = new ArrayList<>();
		String[] idArr = ids.split(",");
		for (String id : idArr) {
			Assert.isTrue(StringUtils.isNumeric(id), ErrorConstants.EVALUATE_PARAM);
			idList.add(Long.valueOf(id));
		}
		res.data(valueEvaluationService.deleteMySteps(idList));
		return res;
	}

	@RequestMapping(value = "/step1", method = RequestMethod.POST)
	public Result step1(String id, @Valid Step1 data, BindingResult bindingResult) {
		Assert.isTrue(StringUtils.isNumeric(id), ErrorConstants.EVALUATE_ID);
		Result res = new Result();
		if (handleBindingError(res, bindingResult)) {
			return res;
		}
		updateSteps(data, 1, "0", res, id);
		return res;
	}

	@RequestMapping(value = "/step2", method = RequestMethod.POST)
	public Result step2(String id, @Valid Step2 data, BindingResult bindingResult) {
		Assert.isTrue(StringUtils.isNumeric(id), ErrorConstants.EVALUATE_ID);
		Result res = new Result();
		if (handleBindingError(res, bindingResult)) {
			return res;
		}
		updateSteps(data, 2, STEP2, res, id);
		return res;
	}

	@RequestMapping(value = "/step3", method = RequestMethod.POST)
	public Result step3(String id, @Valid Step3 data, BindingResult bindingResult) {
		Assert.isTrue(StringUtils.isNumeric(id), ErrorConstants.EVALUATE_ID);
		Result res = new Result();
		if (handleBindingError(res, bindingResult)) {
			return res;
		}
		updateSteps(data, 3, STEP3, res, id);
		return res;
	}

	/**
	 * 到第4步时验证hasIncome为2时加入年收入
	 * @param id
	 * @param hasIncome
	 * @param incomes
	 * @return
	 */
	@RequestMapping(value = "/step4", method = RequestMethod.POST)
	public Result step4(String id, String hasIncome, String incomes) {
		Assert.isTrue(StringUtils.isNumeric(id), ErrorConstants.EVALUATE_ID);
		Result res = new Result();
		Step4 step = new Step4(); //年收入(年份,收入,利润)
		try {
			step.setHasIncome(Integer.valueOf(hasIncome));
			if (step.getHasIncome().equals(2)) {
				List<YearIncome> ja = JSON.parseArray(incomes, YearIncome.class);
				if (ja.size() != 3) {
					res.error(buildError(ErrorConstants.EVALUATE_PARAM));
				} else {
					step.setIncomes(ja);
				}
			}
		} catch (Exception e) {
			res.error(buildError(ErrorConstants.EVALUATE_PARAM));
		}
		if (res.getError().isEmpty()) {
			updateSteps(step, 4, STEP4, res, id);
		}
		return res;
	}

	@RequestMapping(value = "/step5", method = RequestMethod.POST)
	public Result step5(String id, String type, String forecastIncomes) {
		Assert.isTrue(StringUtils.isNumeric(id), ErrorConstants.EVALUATE_ID);
		Result res = new Result();
		Step5 step = new Step5(); //预测收入(市场规模,市场利率,单价,销量,收入)
		try {
			step.setType(Integer.valueOf(type));
			List<ForecastIncome> ja = JSON.parseArray(forecastIncomes, ForecastIncome.class);
			if (ja.size() != 3) {
				res.error(buildError(ErrorConstants.EVALUATE_PARAM));
			} else {
				step.setForecastIncomes(ja);
			}

		} catch (Exception e) {
			res.error(buildError(ErrorConstants.EVALUATE_PARAM));
		}
		if (res.getError().isEmpty()) {
			updateSteps(step, 5, STEP5, res, id);
		}
		return res;
	}

	/**
	 * 
	 * @param id
	 * @return
	 */
	@RequestMapping(value = "/step5/{id}", method = RequestMethod.GET)
	public Result step5Info(@PathVariable String id) {
		Assert.isTrue(StringUtils.isNumeric(id), ErrorConstants.EVALUATE_ID);
		Result res = new Result();
		ValueEvaluation ve = valueEvaluationService.getMyEvaluation(Long.valueOf(id));
		try {
			JSONObject jo = JSON.parseObject(ve.getLog());
			Step4 step4 = ((JSON) jo.get(STEP4)).toJavaObject(Step4.class);
			if (step4.getHasIncome().equals(2)) {
				Step1 step1 = ((JSON) jo.get(STEP1)).toJavaObject(Step1.class);
				res.data(calcForecastIncome(step4.getIncomes(), getIndustryCategoryValue(step1)));
			}
		} catch (Exception e) {
			res.error(buildError(ErrorConstants.EVALUATE_PARAM));
		}
		return res;
	}

	@RequestMapping(value = "/step6", method = RequestMethod.POST)
	public Result step6(String id, @Valid Step6 data, BindingResult bindingResult) {
		Assert.isTrue(StringUtils.isNumeric(id), ErrorConstants.EVALUATE_ID);
		Result res = new Result();
		if (handleBindingError(res, bindingResult)) {
			return res;
		}
		updateSteps(data, 6, STEP6, res, id);
		return res;
	}

	@RequestMapping(value = "/step7", method = RequestMethod.POST)
	public Result step7(String id, @Valid Step7 data, BindingResult bindingResult) {
		Assert.isTrue(StringUtils.isNumeric(id), ErrorConstants.EVALUATE_ID);
		Result res = new Result();
		if (handleBindingError(res, bindingResult)) {
			return res;
		}
		updateSteps(data, 7, STEP7, res, id);
		return res;
	}

	@RequestMapping(value = "/calc/{id}", method = RequestMethod.GET)
	public Result calc(@PathVariable String id) {
		Assert.isTrue(StringUtils.isNumeric(id), ErrorConstants.EVALUATE_ID);
		Result res = new Result();
		ValueEvaluation ve = valueEvaluationService.getMyEvaluation(Long.valueOf(id));
		if (ve == null || ve.getStep() < 7) {
			res.error(buildError(ErrorConstants.EVALUATE_ID));
		} else {
			Long value = calcValue(ve, new HashMap<>());
			res.data(value);
			ValueEvaluation upt = new ValueEvaluation();
			upt.setId(ve.getId());
			upt.setValue(value);
			valueEvaluationService.update(upt);//修改评估价值
		}
		return res;
	}

	@RequestMapping(value = "/report/{id}", method = RequestMethod.GET)
	public Result report(@PathVariable String id, String noCache) {
		Assert.isTrue(StringUtils.isNumeric(id), ErrorConstants.EVALUATE_ID);
		Result res = new Result();
		ValueEvaluation ve = valueEvaluationService.getMyEvaluation(Long.valueOf(id));
		if (ve == null || ve.getStep() < 7) {
			res.error(buildError(ErrorConstants.EVALUATE_ID));
		} else {
			if (noCache != null) {
				/*sysDictService.clear(GOVERNMENT_LOAN_ROR);*/
			}
			Map<String, Object> map = new HashMap<>();
			map.put("customer", TokenManager.getUserToken().getNickname());
			calcValue(ve, map);
			res.data(map);
		}
		return res;
	}

	private Long calcValue(ValueEvaluation ve, Map<String, Object> result) {
		JSONObject log = JSON.parseObject(ve.getLog());
		Step1 step1 = ((JSON) log.get(STEP1)).toJavaObject(Step1.class);
		Step2 step2 = ((JSON) log.get(STEP2)).toJavaObject(Step2.class);
		Step3 step3 = ((JSON) log.get(STEP3)).toJavaObject(Step3.class);
		Step5 step5 = ((JSON) log.get(STEP5)).toJavaObject(Step5.class);
		Step6 step6 = ((JSON) log.get(STEP6)).toJavaObject(Step6.class);
		Step7 step7 = ((JSON) log.get(STEP7)).toJavaObject(Step7.class);
		Integer timeLeft = step1.getTimeLeft();
		timeLeft = timeLeft < 3 ? 3 : timeLeft > 10 ? 10 : timeLeft; // 剩余经济寿命最低3，最大10年
		Map<Integer, IndustryCategory> subs = getIndustryCates(step1.getIndustry());

		Map<Integer, DistrictGlossory> provinces = getProvinces();

		result.put("subIndustries", Stream.of(step1.getSubIndustry().split(",")).map(it -> {
			return subs.get(Integer.valueOf(it)).getName();
		}).collect(Collectors.joining(",")));

		result.put("transferArea", Stream.of(step1.getTransferArea().split(",")).map(it -> {
			return it.equals("0") ? "中国全境" : provinces.get(Integer.valueOf(it)).getName();
		}).collect(Collectors.joining(",")));

		result.put("industry", industryCategoryService.list(0).stream().filter(it -> {
			return it.getId().equals(step1.getIndustry());
		}).findFirst().get().getName());

		BigDecimal industryAverageRate = getIndustryCategoryValue(step1, subs);
		List<Long> userForecast = step5.getForecastIncomes().stream().map(fc -> {
			return fc.getIncome();
		}).collect(Collectors.toList());
		List<Long> sysForecast = calcSysForecast(userForecast, industryAverageRate, timeLeft);
		calcUserForecast(userForecast, timeLeft);
		List<Long> measuredForecast = calcMeasuredForecast(userForecast, sysForecast);

		Map<String, Integer> profitScores = getProfitScores(step2, step3);
		Map<String, Integer> discountRates = getDiscountRates(step7);

		BigDecimal profitRate = calcProfitRate(profitScores, step1.getIndustry(), result);

		/*BigDecimal governmentLoanRoR = new BigDecimal(sysDictService.getValue(GOVERNMENT_LOAN_ROR),
				MathContext.DECIMAL32);*/
		BigDecimal governmentLoanRoR = new BigDecimal(0);
		BigDecimal taxRate = new BigDecimal(step6.getTaxRate());

		BigDecimal discountRate = calcDiscountRate(discountRates, taxRate, governmentLoanRoR);
		result.put("userForecast", userForecast);
		result.put("sysForecast", sysForecast);
		result.put("measuredForecast", measuredForecast);
		result.put("profitRate", profitRate);
		result.put("governmentLoanRoR", governmentLoanRoR);
		result.put("industryAverageRate", industryAverageRate);
		result.put("discountRate", discountRate);
		result.put("benchmarkDate", step1.getBenchmarkDate());
		result.put("timeLeft", timeLeft);
		result.put("name", step1.getName());
		Long value = calcTotal(measuredForecast, profitRate, discountRate, result);
		result.put("value", value);
		result.put("log", log);
		return value;
	}

	private Long calcTotal(List<Long> measuredForecast, BigDecimal profitRate, BigDecimal discountRate,
			Map<String, Object> result) {
		List<Long> profitList = new ArrayList<>();
		BigDecimal total = BigDecimal.ZERO;
		BigDecimal incomeDiscount = BigDecimal.ZERO;
		double discountTerm = 0.5;
		int index = 0;
		BigDecimal discountFactor = BigDecimal.ZERO;
		for (Long val : measuredForecast) {
			incomeDiscount = new BigDecimal(val).multiply(profitRate);
			profitList.add(incomeDiscount.longValue());
			discountFactor = BigDecimal.ONE.divide(BigDecimal.ONE.add(discountRate), 4, RoundingMode.FLOOR);
			discountTerm += index;
			double pow = Math.pow(discountFactor.doubleValue(), discountTerm);
			total = total.add(incomeDiscount.multiply(new BigDecimal(pow)));
			index++;
		}
		result.put("profitList", profitList); // 收入分成额
		return total.longValue();
	}

	private BigDecimal calcDiscountRate(Map<String, Integer> discountRates, BigDecimal taxRate,
			BigDecimal governmentLoanRoR) {
		BigDecimal discountRate = new BigDecimal(discountRates.get("capital"))
				.add(new BigDecimal(discountRates.get("management"))).add(new BigDecimal(discountRates.get("market")))
				.add(new BigDecimal(discountRates.get("political")))
				.add(new BigDecimal(discountRates.get("technical")));
		discountRate = discountRate.add(governmentLoanRoR).divide(HUNDRED.subtract(taxRate), 4, RoundingMode.FLOOR);
		double rate = discountRate.doubleValue();
		rate = rate > 0.3 ? 0.3 : rate < 0.17 ? 0.17 : rate;
		discountRate = new BigDecimal(rate, DEFAULT_PRECISION);
		return discountRate;
	}

	private Map<String, Integer> getDiscountRates(Step7 step7) {
		Map<String, Integer> profitScores = new HashMap<>();
		profitScores.put("capital", getDiscountScore(step7.getCapital()));// 资金风险
		profitScores.put("management", getDiscountScore(step7.getManagement()));// 管理风险
		profitScores.put("market", getDiscountScore(step7.getMarket()));// 市场风险
		profitScores.put("political", getDiscountScore(step7.getPolitical()));// 政策风险
		profitScores.put("technical", getDiscountScore(step7.getTechnical()));// 技术风险
		return profitScores;
	}

	private BigDecimal calcProfitRate(Map<String, Integer> profitScores, Integer industry, Map<String, Object> map) {
		BigDecimal legalFactor = new BigDecimal(0.2, DEFAULT_PRECISION);
		BigDecimal techFactor = new BigDecimal(0.6, DEFAULT_PRECISION);
		BigDecimal fundFactor = legalFactor;

		BigDecimal profitRate = new BigDecimal(profitScores.get("confidentiality")).multiply(legalFactor)
				.multiply(new BigDecimal(0.4, DEFAULT_PRECISION));
		profitRate = profitRate.add(new BigDecimal(profitScores.get("legalStatus")).multiply(legalFactor)
				.multiply(new BigDecimal(0.3, DEFAULT_PRECISION)));
		profitRate = profitRate.add(new BigDecimal(profitScores.get("decidability")).multiply(legalFactor)
				.multiply(new BigDecimal(0.3, DEFAULT_PRECISION)));
		profitRate = profitRate.add(new BigDecimal(profitScores.get("prospect")).multiply(techFactor)
				.multiply(new BigDecimal(0.1, DEFAULT_PRECISION)));
		profitRate = profitRate.add(new BigDecimal(profitScores.get("alternatives")).multiply(techFactor)
				.multiply(new BigDecimal(0.2, DEFAULT_PRECISION)));
		profitRate = profitRate.add(new BigDecimal(profitScores.get("progressiveness")).multiply(techFactor)
				.multiply(new BigDecimal(0.2, DEFAULT_PRECISION)));
		profitRate = profitRate.add(new BigDecimal(profitScores.get("innovativeness")).multiply(techFactor)
				.multiply(new BigDecimal(0.1, DEFAULT_PRECISION)));
		profitRate = profitRate.add(new BigDecimal(profitScores.get("ripeness")).multiply(techFactor)
				.multiply(new BigDecimal(0.2, DEFAULT_PRECISION)));
		profitRate = profitRate.add(new BigDecimal(profitScores.get("rangeOfApplication")).multiply(techFactor)
				.multiply(new BigDecimal(0.1, DEFAULT_PRECISION)));
		profitRate = profitRate.add(new BigDecimal(profitScores.get("defensive")).multiply(techFactor)
				.multiply(new BigDecimal(0.1, DEFAULT_PRECISION)));
		profitRate = profitRate.add(new BigDecimal(profitScores.get("supplyAndDemand")).multiply(fundFactor)
				.multiply(new BigDecimal(0.6, DEFAULT_PRECISION)));
		profitRate = profitRate.add(new BigDecimal(profitScores.get("profitability")).multiply(fundFactor)
				.multiply(new BigDecimal(0.4, DEFAULT_PRECISION)));

		BigDecimal minRate = MIN_RATE;
		BigDecimal maxRate = MAX_RATE;
		if (ProfitRate.containsType(industry)) {
			ProfitRate pr = ProfitRate.getProfitRate(industry);
			minRate = new BigDecimal(pr.getMinRate());
			maxRate = new BigDecimal(pr.getMaxRate());
		}
		map.put("minRate", minRate);
		map.put("maxRate", maxRate);
		profitRate = maxRate.subtract(minRate).multiply(profitRate.multiply(PERCENTAGE)).add(minRate)
				.multiply(PERCENTAGE).setScale(4, RoundingMode.FLOOR);

		return profitRate;
	}

	private Map<String, Integer> getProfitScores(Step2 step2, Step3 step3) {
		// 法律因素权重 20%
		Map<String, Integer> profitScores = new HashMap<>();
		profitScores.put("legalStatus", getScore(step2.getLegalStatus()));// 法律状态
		profitScores.put("confidentiality", getScore(step2.getConfidentiality()));// 保密性
		profitScores.put("decidability", getScore(step2.getDecidability()));// 侵权可判定性
		// 技术因素权重 60%
		profitScores.put("prospect", getScore(step3.getProspect()));// 领域前景
		profitScores.put("alternatives", getScore(step3.getAlternatives()));// 可替代性
		profitScores.put("progressiveness", getScore(step3.getProgressiveness()));// 先进性
		profitScores.put("innovativeness", getScore(step3.getInnovativeness()));// 创新性
		profitScores.put("ripeness", getScore(step3.getRipeness()));// 成熟度
		profitScores.put("rangeOfApplication", getScore(step3.getRangeOfApplication()));// 应用范围
		profitScores.put("defensive", getScore(step3.getDefensive()));// 应用范围
		// 经济因素 20%
		profitScores.put("supplyAndDemand", getScore(step3.getSupplyAndDemand()));// 供求关系
		profitScores.put("profitability", getScore(step3.getProfitability()));// 独立获利能力

		return profitScores;
	}

	private Integer getScore(int option) {
		int idx = option - 1;
		idx = idx < 0 ? 0 : idx >= SCORES.length ? SCORES.length - 1 : idx;
		return SCORES[idx];
	}

	private Integer getDiscountScore(int option) {
		int idx = option - 1;
		idx = idx < 0 ? 0 : idx >= DISCOUNT_SCORES.length ? DISCOUNT_SCORES.length - 1 : idx;
		return DISCOUNT_SCORES[idx];
	}

	private void calcUserForecast(List<Long> userForecast, Integer timeLeft) {
		Assert.isTrue(userForecast.get(0) > 0 && userForecast.get(1) > 0, ErrorConstants.EVALUATE_PARAM);
		BigDecimal second = new BigDecimal(userForecast.get(1));
		BigDecimal lastYear = new BigDecimal(userForecast.get(2));
		BigDecimal rate = lastYear.divide(second, 2, RoundingMode.HALF_UP)
				.subtract(BigDecimal.ONE).add(second
						.divide(new BigDecimal(userForecast.get(0)), 2, RoundingMode.HALF_UP).subtract(BigDecimal.ONE))
				.divide(new BigDecimal(2));
		BigDecimal step = new BigDecimal(0.1, DEFAULT_PRECISION);
		int size = userForecast.size();
		for (int i = size; i < timeLeft; i++) {
			if (i < 6) {
				lastYear = lastYear.multiply(
						BigDecimal.ONE.add(rate.multiply(rate.subtract(step.multiply(new BigDecimal(i - size))))));
			}
			userForecast.add(lastYear.longValue());
		}
	}

	private List<Long> calcSysForecast(List<Long> userForecast, BigDecimal industryAverageRate, Integer timeLeft) {
		List<Long> sysForecast = new ArrayList<>();
		BigDecimal lastYear = BigDecimal.ZERO;
		BigDecimal step = new BigDecimal(0.1, DEFAULT_PRECISION);
		industryAverageRate = industryAverageRate.multiply(PERCENTAGE);
		for (int i = 0; i < timeLeft; i++) {
			if (i == 0) {
				lastYear = new BigDecimal(userForecast.get(0)).multiply(new BigDecimal(0.9, DEFAULT_PRECISION));
			} else if (i < 6) {
				lastYear = lastYear.multiply(BigDecimal.ONE.add(
						industryAverageRate.multiply(BigDecimal.ONE.subtract(step.multiply(new BigDecimal(i - 1))))));
			}
			sysForecast.add(lastYear.longValue());
		}
		return sysForecast;
	}

	private List<Long> calcMeasuredForecast(List<Long> userForecast, List<Long> sysForecast) {
		List<Long> measuredForecast = new ArrayList<>();
		for (int i = 0; i < sysForecast.size(); i++) {
			measuredForecast.add((userForecast.get(i) + sysForecast.get(i)) >> 1);
		}
		return measuredForecast;
	}

	/**
	 * 更新评估步骤
	 * @param step
	 * @param nextStep
	 * @param key
	 * @param res
	 * @param id
	 */
	private void updateSteps(Object step, Integer nextStep, String key, Result res, String id) {
		ValueEvaluation ve = valueEvaluationService.getMyEvaluation(Long.valueOf(id));
		Assert.notNull(ve, ErrorConstants.EVALUATE_ID);
		ve.setStep(Math.max(nextStep, ve.getStep()));
		if (nextStep == 1) {
			ve.setName(((Step1) step).getName());
		}
		ve.setValue(0l);
		JSONObject jo = JSON.parseObject(ve.getLog());
		jo.put(key, step);
		ve.setLog(jo.toJSONString());
		res.data(valueEvaluationService.update(ve));
	}

	private boolean handleBindingError(Result res, BindingResult bindingResult) {
		if (bindingResult.hasErrors()) {
			LoggerUtils.debug(logger, "参数错误：[%s], [%s], [%s]", bindingResult.getFieldError().getDefaultMessage(),
					bindingResult.getFieldError().getField(), bindingResult.getFieldError().getRejectedValue());
			res.getError().add(buildError(ErrorConstants.EVALUATE_PARAM));
			return true;
		}
		return false;
	}

	private BigDecimal getIndustryCategoryValue(Step1 step1) {
		return getIndustryCategoryValue(step1, getIndustryCates(step1.getIndustry()));
	}

	/**
	 * 获得行业分类
	 * @param pid
	 * @return
	 */
	private Map<Integer, IndustryCategory> getIndustryCates(Integer pid) {
		return industryCategoryService.list(pid).stream()
				.collect(Collectors.toMap(IndustryCategory::getId, (it) -> it));
	}
	
	private Map<Integer, DistrictGlossory> getProvinces() {
		return districtGlossoryService.list(0).stream().collect(Collectors.toMap(DistrictGlossory::getId, (it) -> it));
	}

	/**
	 * 获得行业分类平均值
	 * @param step1
	 * @param cates
	 * @return
	 */
	private BigDecimal getIndustryCategoryValue(Step1 step1, Map<Integer, IndustryCategory> cates) {
		List<Integer> subIds = Stream.of(step1.getSubIndustry().split(",")).map(it -> {
			return Integer.valueOf(it);
		}).collect(Collectors.toList());
		BigDecimal average = BigDecimal.ZERO;
		int count = 0;
		for (Integer id : subIds) {
			if (cates.containsKey(id)) {
				average = average.add(cates.get(id).getValue());
				count++;
			}
		}
		return average.divide(new BigDecimal(count == 0 ? 1 : count), 2, RoundingMode.HALF_UP);//average四舍五入保留2位小数
	}

	/**
	 * 预计收入处理
	 * @param incomes
	 * @param growth
	 * @return
	 */
	private Long[] calcForecastIncome(List<YearIncome> incomes, BigDecimal growth) {
		BigDecimal useGrowth = growth.multiply(PERCENTAGE);
		BigDecimal base = new BigDecimal(incomes.get(0).getIncome());
		if (!incomes.get(1).getIncome().equals(0)) {
			useGrowth = base.divide(new BigDecimal(incomes.get(1).getIncome()), 2, RoundingMode.CEILING)
					.subtract(BigDecimal.ONE);//保留2位天花板数减去1
		}
		Long[] res = new Long[3];
		BigDecimal one = base.multiply(useGrowth.add(BigDecimal.ONE));
		useGrowth = useGrowth.multiply(new BigDecimal(0.9, DEFAULT_PRECISION));
		BigDecimal two = one.multiply(useGrowth.add(BigDecimal.ONE));
		useGrowth = useGrowth.multiply(new BigDecimal(0.8, DEFAULT_PRECISION));
		res[2] = two.multiply(useGrowth.add(BigDecimal.ONE)).longValue();
		res[0] = one.longValue();
		res[1] = two.longValue();
		return res;
	}
}
