package com.dayou.report.calculation.cityPrice.process;

import com.dayou.report.calculation.cityPrice.bo.*;
import com.dayou.report.format.BigDecimalFormatUtil;
import com.dayou.report.kmeans.Cluster;
import com.dayou.report.kmeans.KMeansHelper;
import com.dayou.report.kmeans.Point;
import com.google.common.collect.Lists;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 类说明：城区土地定级与基准地价计算类
 *
 * @author: wucl
 * @since: 2023/9/14
 * created with IntelliJ IDEA.
 */
@Component
public class CityPriceCalculateProcess {


    private static final String ACREAGE= "占地面积V1";
    private static final String SHOPNUM= "店铺数量V2";
    private static final String SHOPPINGNUM= "购物人次V3";
    private static final String TURNOVER= "营业额V4";
    private static final String RENT= "平均租金V5";

    private static final String V6= "V6";

    /**
     * 城区商服中心评定指标权重值（因素成对比较法）
     * @param businessCenterIndexWeightBOS
     * @return
     */
    public List<BusinessCenterIndexWeightBO> businessCenterIndexWeight(List<BusinessCenterIndexWeightBO> businessCenterIndexWeightBOS){

        BigDecimal sumTotal = BigDecimal.ZERO;
        for (BusinessCenterIndexWeightBO bo : businessCenterIndexWeightBOS){
            BigDecimal total = bo.getAcreage().add(bo.getShopNum()).add(bo.getShoppingNum()).add(bo.getTurnover()).add(bo.getRent()).add(bo.getV6());
            bo.setTotal(total);
            sumTotal = sumTotal.add(total);
        }
        for (BusinessCenterIndexWeightBO bo : businessCenterIndexWeightBOS){
            bo.setWeight(bo.getTotal().divide(sumTotal,2, RoundingMode.HALF_UP));
        }

        businessCenterIndexWeightBOS.add(BusinessCenterIndexWeightBO.builder().name("合计").total(sumTotal).weight(BigDecimal.ONE.setScale(2)).build());

        return businessCenterIndexWeightBOS;
    }

    /**
     * 城区商服中心各评定指标归一化值及综合指标值表
     * @param businessCenterBaseBOS
     * @param weights
     * @return
     */
    public List<BusinessCenterFormatBO> businessCenterFormat(List<BusinessCenterBaseBO> businessCenterBaseBOS, Map<String,BigDecimal> weights){
        List<BigDecimal> acreageList = businessCenterBaseBOS.stream().map(BusinessCenterBaseBO::getAcreage).collect(Collectors.toList());
        BigDecimal acreageMax = acreageList.stream().reduce(acreageList.get(0), BigDecimal::max);

        List<BigDecimal> shipList = businessCenterBaseBOS.stream().map(BusinessCenterBaseBO::getShopNum).collect(Collectors.toList());
        BigDecimal shipListMax = shipList.stream().reduce(shipList.get(0), BigDecimal::max);

        List<BigDecimal> shoppingNumList = businessCenterBaseBOS.stream().map(BusinessCenterBaseBO::getShoppingNum).collect(Collectors.toList());
        BigDecimal shoppingNumMax = shoppingNumList.stream().reduce(shoppingNumList.get(0), BigDecimal::max);

        List<BigDecimal> turnoverList = businessCenterBaseBOS.stream().map(BusinessCenterBaseBO::getTurnover).collect(Collectors.toList());
        BigDecimal turnoverMax = turnoverList.stream().reduce(turnoverList.get(0), BigDecimal::max);

        List<BigDecimal> rentList = businessCenterBaseBOS.stream().map(BusinessCenterBaseBO::getRent).collect(Collectors.toList());
        BigDecimal rentMax = rentList.stream().reduce(rentList.get(0), BigDecimal::max);

        List<BusinessCenterFormatBO> formatList = Lists.newArrayList();
        businessCenterBaseBOS.stream().forEach(bo->{
            BusinessCenterFormatBO formatBO = BusinessCenterFormatBO.builder().no(bo.getNo()).name(bo.getName())
                    .acreage(BigDecimalFormatUtil.divideResult_Multiply100Scale2HalfUp(bo.getAcreage(),acreageMax))
                    .shopNum(BigDecimalFormatUtil.divideResult_Multiply100Scale2HalfUp(bo.getShopNum(),shipListMax))
                    .shoppingNum(BigDecimalFormatUtil.divideResult_Multiply100Scale2HalfUp(bo.getShoppingNum(),shoppingNumMax))
                    .turnover(BigDecimalFormatUtil.divideResult_Multiply100Scale2HalfUp(bo.getTurnover(),turnoverMax))
                    .rent(BigDecimalFormatUtil.divideResult_Multiply100Scale2HalfUp(bo.getRent(),rentMax)).build();
            formatList.add(formatBO);
        });

        formatList.stream().forEach(bo->{
            BigDecimal comprehensive = bo.getAcreage().multiply(weights.get(ACREAGE))
                    .add(bo.getShopNum().multiply(weights.get(SHOPNUM)))
                    .add(bo.getShoppingNum().multiply(weights.get(SHOPPINGNUM)))
                    .add(bo.getTurnover().multiply(weights.get(TURNOVER)))
                    .add(bo.getRent().multiply(weights.get(RENT))).setScale(2,RoundingMode.HALF_UP);
            bo.setComprehensive(comprehensive);
        });
        return formatList;
    }

    /**
     * 城区商服中心级别划分及综合指标值
     * @param comprehensive
     * @return
     */
    public List<BusinessCenterLevelBO> businessCenterLeve(Map<String,BigDecimal> comprehensive){
        List<Cluster> clusters = KMeansHelper.kMeansClustering(comprehensive, 2);
        List<BusinessCenterLevelBO> bos= Lists.newArrayList();
        clusters.stream().forEach(x->{
            List<Point> sameList = x.getSameList();
            List<BusinessCenterLevelBO> collect = sameList.stream().map(y -> {
                BusinessCenterLevelBO build = BusinessCenterLevelBO.builder().level(x.getCorePoint().getName()).name(y.getName())
                        .comprehensive(BigDecimal.valueOf(y.getX()))
                        .avgComprehensive(BigDecimal.valueOf(x.getCorePoint().getX())).avgComprehensiveFormat(BigDecimal.valueOf(x.getCorePoint().getX()))
                        .build();
                return build;
            }).collect(Collectors.toList());
            bos.addAll(collect);
        });
        List<BusinessCenterLevelBO> bosSorted = bos.stream().sorted((b1, b2) -> b2.getAvgComprehensiveFormat().compareTo(b1.getAvgComprehensiveFormat())).collect(Collectors.toList());
        return bosSorted;
    }

    /**
     * 城区商服中心规模指数表
     * @param businessCenterLevelBOS
     * @return
     */
    public List<BusinessCenterScaleBO> businessCenterScale(List<BusinessCenterLevelBO> businessCenterLevelBOS){
        Set<BusinessCenterScaleBO> bos = businessCenterLevelBOS.stream().map(x -> {
            //BusinessCenterScaleBO scale = BusinessCenterScaleBO.builder().level(k).avgComprehensive(v).scaleOrigin(v).scaleValue(v).build();
            BusinessCenterScaleBO scale = BusinessCenterScaleBO.builder().level(x.getLevel()).avgComprehensive(x.getAvgComprehensiveFormat())
                    .scaleOrigin(x.getAvgComprehensiveFormat()).scaleValue(BigDecimalFormatUtil.format_Divide10Scale0HalfUpMultiply10(x.getAvgComprehensiveFormat()))
                    .build();
            return scale;
        }).collect(Collectors.toSet());
        List<BusinessCenterScaleBO> bosSorted = bos.stream().sorted((b1, b2) -> b2.getScaleValue().compareTo(b1.getScaleValue())).collect(Collectors.toList());
        return bosSorted;
    }

    public List<BusinessCenterCapacityScoreBO> businessCenterCapacityScore(List<BusinessCenterScaleBO> scales){
        List<BusinessCenterCapacityScoreBO> bos= Lists.newArrayList();
        for (int i=0 ; i< scales.size(); i++){
            if (scales.size()-1 == i){
                BusinessCenterCapacityScoreBO bo = BusinessCenterCapacityScoreBO.builder().level(scales.get(i).getLevel())
                        .score(scales.get(i).getScaleValue()).serviceRadius(new BigDecimal("11000")).build();
                bos.add(bo);
            }else {
                BusinessCenterCapacityScoreBO bo = BusinessCenterCapacityScoreBO.builder().level(scales.get(i).getLevel())
                        .score(scales.get(i).getScaleValue().subtract(scales.get(i + 1).getScaleValue())).serviceRadius(new BigDecimal("2200")).build();
                bos.add(bo);
            }
        }
        return bos;
    }

    /**
     * 城区商服繁华影响度作用分值表(等距间距表)
     * @param scoreBOS
     * @return
     */
    public List<BusinessCenterEffectDistanceBo> businessCenterEffectDistance(List<BusinessCenterCapacityScoreBO> scoreBOS){
        List<BusinessCenterEffectDistanceBo> collect = scoreBOS.stream().map(x -> {
            BusinessCenterEffectDistanceBo effectDistance = new BusinessCenterEffectDistanceBo();
            effectDistance.setEffectDistance(x.getLevel() + "D=" + x.getServiceRadius() + "m");
            effectDistance.setRelativelyDistance("作用分(e)" + x.getScore());
            effectDistance.setDistance0(BigDecimal.valueOf(Math.pow(x.getScore().doubleValue(), 1)).setScale(2, RoundingMode.HALF_UP));
            effectDistance.setDistance1(BigDecimal.valueOf(Math.pow(x.getScore().doubleValue(), 0.1)).setScale(2, RoundingMode.HALF_UP));
            effectDistance.setDistance2(BigDecimal.valueOf(Math.pow(x.getScore().doubleValue(), 0.2)).setScale(2, RoundingMode.HALF_UP));
            effectDistance.setDistance3(BigDecimal.valueOf(Math.pow(x.getScore().doubleValue(), 0.3)).setScale(2, RoundingMode.HALF_UP));
            effectDistance.setDistance4(BigDecimal.valueOf(Math.pow(x.getScore().doubleValue(), 0.4)).setScale(2, RoundingMode.HALF_UP));
            effectDistance.setDistance5(BigDecimal.valueOf(Math.pow(x.getScore().doubleValue(), 0.5)).setScale(2, RoundingMode.HALF_UP));
            effectDistance.setDistance6(BigDecimal.valueOf(Math.pow(x.getScore().doubleValue(), 0.6)).setScale(2, RoundingMode.HALF_UP));
            effectDistance.setDistance7(BigDecimal.valueOf(Math.pow(x.getScore().doubleValue(), 0.7)).setScale(2, RoundingMode.HALF_UP));
            effectDistance.setDistance8(BigDecimal.valueOf(Math.pow(x.getScore().doubleValue(), 0.8)).setScale(2, RoundingMode.HALF_UP));
            effectDistance.setDistance9(BigDecimal.valueOf(Math.pow(x.getScore().doubleValue(), 0.9)).setScale(2, RoundingMode.HALF_UP));
            effectDistance.setDistance10(BigDecimal.valueOf(Math.pow(x.getScore().doubleValue(), 0)).setScale(2, RoundingMode.HALF_UP));
            return effectDistance;
        }).collect(Collectors.toList());
        return collect;
    }

}
