package cn.cecep.talroad.service.impl.analysis;

import cn.cecep.talroad.common.core.utils.DateUtils;
import cn.cecep.talroad.domain.analysis.SRaAbNalysisLowCar;
import cn.cecep.talroad.mapper.analysis.SRaAbNalysisLowCarMapper;
import cn.cecep.talroad.service.analysis.ISRaAbNalysisLowCarService;
import cn.cecep.talroad.util.ExportWordUtil;
import cn.cecep.talroad.vo.EChartsVO;
import cn.cecep.talroad.vo.query.analysis.SRaAbNalysisLowCarQuery;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 管控期车辆异常分析Service业务层处理
 *
 * @author szhpt
 * @date 2023-03-24
 */
@Service
public class SRaAbNalysisLowCarServiceImpl extends ServiceImpl<SRaAbNalysisLowCarMapper, SRaAbNalysisLowCar> implements ISRaAbNalysisLowCarService {
    @Autowired
    private SRaAbNalysisLowCarMapper sRaAbNalysisLowCarMapper;

    /**
     * 查询管控期车辆异常分析列表
     *
     * @param sRaAbNalysisLowCar 管控期车辆异常分析
     * @return 管控期车辆异常分析
     */
    @Override
    public List<SRaAbNalysisLowCar> selectSRaAbNalysisLowCarList(SRaAbNalysisLowCarQuery sRaAbNalysisLowCar) {
        return sRaAbNalysisLowCarMapper.selectSRaAbNalysisLowCarList(sRaAbNalysisLowCar);
    }

    @Override
    public EChartsVO chartData(List<SRaAbNalysisLowCar> list, SRaAbNalysisLowCarQuery sRaAbNalysisLowCar) {
        Calendar calendar = new GregorianCalendar();
        if(ObjectUtil.isNotEmpty(sRaAbNalysisLowCar.getEndAnalyseTime())){
            calendar.setTime(sRaAbNalysisLowCar.getEndAnalyseTime());
            // 把日期往后增加一天,整数  往后推,负数往前移动
            calendar.add(Calendar.DATE, 1);
            calendar.add(Calendar.HOUR_OF_DAY,-1);
        }
        EChartsVO eChartsVO = new EChartsVO();
        List<String> dateMonthList = CollUtil.map(DateUtil.rangeToList(sRaAbNalysisLowCar.getStartAnalyseTime(),
                        calendar.getTime(), DateField.HOUR),
                x -> DateUtil.format(x, "yyyy-MM-dd HH"), true);
        eChartsVO.setXData(dateMonthList);
        List<Map<String, String>> items = new ArrayList<>();
        items.add(new HashMap<String, String>() {{
            put("name", "国四及以下车辆");
            put("prop", "inOutNumber");
        }});
        items.add(new HashMap<String, String>() {{
            put("name", "国五车辆");
            put("prop", "fiveNumber");
        }});
        items.add(new HashMap<String, String>() {{
            put("name", "国六车辆");
            put("prop", "sixNumber");
        }});
        items.add(new HashMap<String, String>() {{
            put("name", "新能源车辆");
            put("prop", "neNumber");
        }});
        long l = System.currentTimeMillis();
        List<SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData> data =
                BeanUtil.copyToList(list, SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData.class);
       /* data.forEach(d -> {
            Date analyseTime = d.getAnalyseTime();
            String format = DateUtil.format(analyseTime, "yyyy-MM-dd HH");
            d.setAnalyseTimeStr(format);
        });*/
        Map<String, Long> fiveMap = data.stream().collect(Collectors.groupingBy(SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData::getAnalyseTimeStr, Collectors.collectingAndThen(
                Collectors.summingLong(dataItem -> Optional.ofNullable(dataItem.getFiveNumber()).orElse(0L)),
                sum -> sum == 0 ? null : sum
        )));
        Map<String, Long> sixMap = data.stream().collect(Collectors.groupingBy(SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData::getAnalyseTimeStr, Collectors.collectingAndThen(
                Collectors.summingLong(dataItem -> Optional.ofNullable(dataItem.getSixNumber()).orElse(0L)),
                sum -> sum == 0 ? null : sum
        )));
        Map<String, Long> newMap = data.stream().collect(Collectors.groupingBy(SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData::getAnalyseTimeStr, Collectors.collectingAndThen(
                Collectors.summingLong(dataItem -> Optional.ofNullable(dataItem.getNeNumber()).orElse(0L)),
                sum -> sum == 0 ? null : sum
        )));
        Map<String, Long> inOutMap = data.stream().collect(Collectors.groupingBy(SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData::getAnalyseTimeStr,Collectors.collectingAndThen(
                Collectors.summingLong(dataItem -> Optional.ofNullable(dataItem.getInOutNumber()).orElse(0L)),
                sum -> sum == 0 ? null : sum
        )));
        List<SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData> all = new ArrayList<>();
        long l1 = System.currentTimeMillis();
        System.err.println((l1-l)/1000+"秒");
        dateMonthList.forEach(d -> {
            SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData sd = new SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData();
           /* List<SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData> collect = data.stream().filter(dt -> dt.getAnalyseTimeStr().equals(d)).collect(Collectors.toList());
//            sd.setFiveNumber(collect.stream().mapToLong(SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData::getFiveNumber).sum());
            sd.setFiveNumber(collect.stream().filter(e -> e.getFiveNumber() != null).mapToLong(SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData::getFiveNumber).sum());
            sd.setSixNumber(collect.stream().filter(e -> e.getSixNumber() != null).mapToLong(SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData::getSixNumber).sum());
            sd.setNeNumber(collect.stream().filter(e -> e.getNeNumber() != null).mapToLong(SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData::getNeNumber).sum());
            sd.setInOutNumber(collect.stream().filter(e -> e.getInOutNumber() != null).mapToLong(SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData::getInOutNumber).sum());*/
            sd.setFiveNumber(fiveMap.get(d));
            sd.setSixNumber(sixMap.get(d));
            sd.setNeNumber(newMap.get(d));
            sd.setInOutNumber(inOutMap.get(d));
            sd.setAnalyseTimeStr(d);
            all.add(sd);
        });

        List<EChartsVO.SeriesObj> series = items.stream().map(item -> {
            EChartsVO.SeriesObj ser = new EChartsVO.SeriesObj();
            ser.setName(item.get("name"));
            List<Object> values = all.stream().map(o -> BeanUtil.getProperty(o, item.get("prop"))).collect(Collectors.toList());
            ser.setValues(values);
            return ser;
        }).collect(Collectors.toList());
        long l2 = System.currentTimeMillis();
        System.err.println((l2-l1)/1000+"秒");
        eChartsVO.setSeries(series);
        return eChartsVO;
    }

    /**
     * @Method parkChartData
     * @Author wyg
     * 近一周进出厂车辆趋势
     * @Exception
     * @Date 2023/6/20 09:48
     */
    @Override
    public EChartsVO parkChartData(List<SRaAbNalysisLowCar> list) {
        EChartsVO eChartsVO = new EChartsVO();
        List<String> dateMonthList = CollUtil.map(DateUtil.rangeToList(DateUtils.addDateDays(DateUtils.getNowDate(), -6), DateUtils.getNowDate(), DateField.HOUR),
                x -> DateUtil.format(x, "yyyy-MM-dd HH"), true);
        eChartsVO.setXData(dateMonthList);
        List<Map<String, String>> items = new ArrayList<>();
        items.add(new HashMap<String, String>() {{
            put("name", "进厂");
            put("prop", "inPark");
        }});
        items.add(new HashMap<String, String>() {{
            put("name", "出厂");
            put("prop", "outPark");
        }});

        List<SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData> data =
                BeanUtil.copyToList(list, SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData.class);
        data.forEach(d -> {
            Date analyseTime = d.getAnalyseTime();
            String format = DateUtil.format(analyseTime, "yyyy-MM-dd HH");
            d.setAnalyseTimeStr(format);
        });

        List<SRaAbNalysisLowCar.SRaAbNalysisLowParkEChartData> all1 = new ArrayList<>();
        dateMonthList.forEach(d -> {
            List<SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData> collect = data.stream().filter(dt -> dt.getAnalyseTimeStr().equals(d)).collect(Collectors.toList());
            SRaAbNalysisLowCar.SRaAbNalysisLowParkEChartData sd1 = new SRaAbNalysisLowCar.SRaAbNalysisLowParkEChartData();
            sd1.setInPark(
                    collect.stream().filter(e -> e.getFiveNumber() == null).mapToLong(SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData::getDataId).sum() +
                            collect.stream().filter(e -> e.getSixNumber() == null).mapToLong(SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData::getDataId).sum() +
                            collect.stream().filter(e -> e.getNeNumber() == null).mapToLong(SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData::getDataId).sum() +
                            collect.stream().filter(e -> e.getInOutNumber() == null).mapToLong(SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData::getDataId).sum()
            );
            sd1.setOutPark(
                    collect.stream().filter(e -> e.getFiveNumber() != null).mapToLong(SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData::getFiveNumber).sum() +
                            collect.stream().filter(e -> e.getSixNumber() != null).mapToLong(SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData::getSixNumber).sum() +
                            collect.stream().filter(e -> e.getNeNumber() != null).mapToLong(SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData::getNeNumber).sum() +
                            collect.stream().filter(e -> e.getInOutNumber() != null).mapToLong(SRaAbNalysisLowCar.SRaAbNalysisLowCarEChartData::getInOutNumber).sum()
            );
            all1.add(sd1);
        });

        List<EChartsVO.SeriesObj> series = items.stream().map(item -> {
            EChartsVO.SeriesObj ser = new EChartsVO.SeriesObj();
            ser.setName(item.get("name"));
            ser.setSeriesType("bar");
            List<Object> values = all1.stream().map(o -> BeanUtil.getProperty(o, item.get("prop"))).collect(Collectors.toList());
            ser.setValues(values);
            return ser;
        }).collect(Collectors.toList());
        eChartsVO.setSeries(series);
        return eChartsVO;
    }


    /**
     * 车辆出入异常报告导出
     * @param response
     * @param sRaAbNalysisLowCar
     */
    @Override
    public void exportWordReport(HttpServletResponse response, SRaAbNalysisLowCarQuery sRaAbNalysisLowCar) throws TemplateException, IOException {
        //初始化各个参数
        BigDecimal level4Count = new BigDecimal(0),
                level5Count =  new BigDecimal(0),
                level6Count =  new BigDecimal(0),
                newPowerCount =  new BigDecimal(0),
                sumCount =  new BigDecimal(0);
        StringBuilder level4FactoryListStr = new StringBuilder(),
                level5FactoryListStr = new StringBuilder();
        //获取list列表
        List<SRaAbNalysisLowCar> list = list(SRaAbNalysisLowCarQuery.createLambdaQueryWrapper(sRaAbNalysisLowCar));
        //进行累加总数量，并分类统计国四国五车辆列表
        Set<String> Level4FactoryList = new HashSet<>(),Level5FactoryList = new HashSet<>();
        for (SRaAbNalysisLowCar raAbNalysisLowCar : list) {
            if(raAbNalysisLowCar.getInOutNumber() != null){//国四，需要统计企业名称
                level4Count = level4Count.add(new BigDecimal(raAbNalysisLowCar.getInOutNumber()));
                sumCount = sumCount.add(new BigDecimal(raAbNalysisLowCar.getInOutNumber()));
                Level4FactoryList.add(raAbNalysisLowCar.getFactoryName());
            }
            if(raAbNalysisLowCar.getFiveNumber() != null){//国五，需要统计企业名称
                level5Count = level5Count.add(new BigDecimal(raAbNalysisLowCar.getFiveNumber()));
                sumCount = sumCount.add(new BigDecimal(raAbNalysisLowCar.getFiveNumber()));
                Level5FactoryList.add(raAbNalysisLowCar.getFactoryName());
            }
            if(raAbNalysisLowCar.getSixNumber() != null){
                level6Count = level6Count.add(new BigDecimal(raAbNalysisLowCar.getSixNumber()));
                sumCount = sumCount.add(new BigDecimal(raAbNalysisLowCar.getSixNumber()));
            }
            if(raAbNalysisLowCar.getNeNumber() != null){
                newPowerCount = newPowerCount.add(new BigDecimal(raAbNalysisLowCar.getNeNumber()));
                sumCount = sumCount.add(new BigDecimal(raAbNalysisLowCar.getNeNumber()));
            }
        }
        for (String s : Level4FactoryList) {
            level4FactoryListStr.append(","+s);
        }
        for (String s : Level5FactoryList) {
            level5FactoryListStr.append(","+s);
        }
        //防止初0异常，当总数为0其余四个数量必定为0
        if(sumCount.compareTo(BigDecimal.ZERO) == 0){
            sumCount = sumCount.add(BigDecimal.ONE);
        }
        Map<String,Object> map = new HashMap();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
        map.put("dataTime",simpleDateFormat.format(sRaAbNalysisLowCar.getStartAnalyseTime())+"-"+simpleDateFormat.format(sRaAbNalysisLowCar.getEndAnalyseTime()));
        map.put("Level4Count",level4Count);
        map.put("Level5Count",level5Count);
        map.put("Level6Count",level6Count);
        map.put("NewPowerCount",newPowerCount);
        map.put("Level4Rate",level4Count.divide(sumCount, 2,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).toString());
        map.put("Level5Rate",level5Count.divide(sumCount, 2,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).toString());
        map.put("Level6Rate",level6Count.divide(sumCount, 2,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).toString());
        map.put("NewPowerRate",newPowerCount.divide(sumCount, 2,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).toString());
        map.put("Level4FactoryList",level4FactoryListStr.length()>0?"\t存在国四及以下车辆进出厂情况的企业为："+level4FactoryListStr.substring(1).toString()+"。<w:br/>":"");
        map.put("Level5FactoryList",level5FactoryListStr.length()>0?"\t存在国五车辆进出厂情况的企业为："+level5FactoryListStr.substring(1).toString()+"。<w:br/>":"");
        ExportWordUtil.exportToWord(map,response,"wordReport/AccessControlTotalReport.ftl","wordReport/AccessControlTotalReport.docx","企业门禁统计分析报表.docx");
    }
}
