package com.jjt.biz.service.impl;

import com.jjt.biz.service.IApiAllService;
import com.jjt.biz.vo.*;
import com.jjt.calc.domain.TwinCalcDay;
import com.jjt.calc.service.ITwinCalcDayService;
import com.jjt.common.constant.CacheConstants;
import com.jjt.common.core.redis.RedisCache;
import com.jjt.common.utils.DateUtils;
import com.jjt.ws.domain.TwinRzCalcMonth;
import com.jjt.ws.domain.TwinWorkshopCalc;
import com.jjt.ws.service.ITwinRzCalcMonthService;
import com.jjt.ws.service.ITwinWorkshopCalcService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 首页统计数据
 *
 * @author wukai
 * @date 2024/5/4 20:35
 */
@Service
@Slf4j
public class ApiAllServiceImpl implements IApiAllService {
    @Resource
    private RedisCache redisCache;
    @Resource
    private ITwinWorkshopCalcService wsCalcService;
    @Resource
    private ITwinRzCalcMonthService rzCalcMonthService;
    @Resource
    private ITwinCalcDayService calcDayService;

    /**
     * 获取当前库存数据
     *
     * @return 库存数据
     */
    @Override
    public Map<String, Object> stock() {
        return redisCache.getCacheObject(CacheConstants.VMS_STOCK);
    }

    /**
     * 获取本月平均值
     *
     * @return 结果
     */
    @Override
    public AvgMonthVO avgMonth() {
        LocalDateTime ldt = LocalDateTime.now();
        YearMonth targetMonth = YearMonth.from(ldt);
        if (ldt.getDayOfMonth() < 2 || ldt.getDayOfMonth() == 2 && ldt.getHour() < 8) {
            //2号8点之前 取上一个月
            targetMonth = targetMonth.minusMonths(1);
        }
        String month = targetMonth.format(DateTimeFormatter.ofPattern("yyyy-MM"));
        Map<String, Object> params = new HashMap<>(16);
        params.put("month", month);

        BigDecimal costTotal = BigDecimal.ZERO;
        BigDecimal costJb = BigDecimal.ZERO;
        BigDecimal yieldJb = BigDecimal.ZERO;
        BigDecimal jdl = BigDecimal.ZERO;
        BigDecimal costRz = BigDecimal.ZERO;
        BigDecimal yieldRz = BigDecimal.ZERO;

        AvgMonthVO vo = new AvgMonthVO();
        TwinWorkshopCalc twinWorkshopCalc = new TwinWorkshopCalc();
        twinWorkshopCalc.setParams(params);
        List<TwinWorkshopCalc> wsList = wsCalcService.selectTwinWorkshopCalcList(twinWorkshopCalc);
        Map<Date, List<TwinWorkshopCalc>> wsMap = wsList.stream().collect(Collectors.groupingBy(TwinWorkshopCalc::getDataDate));
        for (Date d : wsMap.keySet()) {
            List<TwinWorkshopCalc> list = wsMap.get(d);
            for (TwinWorkshopCalc ws : list) {
                if ("WS02-D".equals(ws.getWsCode())) {
                    //经编费用
                    costJb = costJb.add(ws.getTotalPrice());
                }
                costTotal = costTotal.add(ws.getTotalPrice());
            }
        }

        costTotal = costTotal.divide(BigDecimal.valueOf(wsMap.size()), 2, RoundingMode.HALF_UP);
        //这里是算的经编总费用
        costJb = costJb.divide(BigDecimal.valueOf(wsMap.size()), 1, RoundingMode.HALF_UP);

        List<TwinCalcDay> dayList = calcDayService.selectTwinCalcDayListByMonth(month);
        Map<Date, List<TwinCalcDay>> dayMap = dayList.stream().collect(Collectors.groupingBy(TwinCalcDay::getTime));
        for (Date d : dayMap.keySet()) {
            List<TwinCalcDay> list = dayMap.get(d);
            // 计算 length 总和
            BigDecimal totalLength = list.stream()
                    .map(TwinCalcDay::getLength)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            yieldJb = yieldJb.add(totalLength);
            // 计算 jdl 总和
            BigDecimal totalJdl = list.stream()
                    .map(TwinCalcDay::getEfficiency)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal avgJdl = totalJdl.multiply(BigDecimal.valueOf(100)).divide(BigDecimal.valueOf(list.size()), 4, RoundingMode.HALF_UP);
            jdl = jdl.add(avgJdl);
        }

        yieldJb = yieldJb.divide(BigDecimal.valueOf(dayMap.size()), 0, RoundingMode.HALF_UP);
        jdl = jdl.divide(BigDecimal.valueOf(dayMap.size()), 2, RoundingMode.HALF_UP);


        TwinRzCalcMonth twinRzCalcMonth = new TwinRzCalcMonth();
        twinRzCalcMonth.setParams(params);
        List<TwinRzCalcMonth> rzList = rzCalcMonthService.selectTwinRzCalcMonthList(twinRzCalcMonth);
        for (TwinRzCalcMonth calcMonth : rzList) {
            costRz = costRz.add(calcMonth.getLengthPrice());
            yieldRz = yieldRz.add(calcMonth.getLength());
        }

        costRz = costRz.divide(BigDecimal.valueOf(rzList.size()), 2, RoundingMode.HALF_UP);
        yieldRz = yieldRz.divide(BigDecimal.valueOf(rzList.size()), 0, RoundingMode.HALF_UP);
        //这里算平均每米费用
        costJb = costJb.divide(yieldJb, 2, RoundingMode.HALF_UP);
        vo.setCostRz(costRz);
        vo.setYieldRz(yieldRz);
        vo.setCostTotal(costTotal);
        vo.setCostJb(costJb);
        vo.setYieldJb(yieldJb);
        vo.setJdl(jdl);
        return vo;
    }

    /**
     * 获取生产情况
     *
     * @return 结果
     */
    @Override
    public CurrYieldVO currYield() {
        CurrYieldVO vo = new CurrYieldVO();
        vo.mock();
//        IndexData todayData = redisCache.getCacheObject(CacheConstants.INDEX_CALC);
//        IndexData currData = redisCache.getCacheObject(CacheConstants.INDEX_ALARM);
//        vo.getJb().setYield(BigDecimal.valueOf(todayData.getEfficiency().getTotalLength()).setScale(0, RoundingMode.HALF_UP));
//        vo.getJb().setYieldMax(BigDecimal.valueOf(50000));
//        BigDecimal jdl = BigDecimal.valueOf(todayData.getEfficiency().getAEfficiency() + todayData.getEfficiency().getBEfficiency()).divide(BigDecimal.valueOf(2), 0, RoundingMode.HALF_UP);
//        if (todayData.getEfficiency().getBEfficiency() == 0f) {
//            jdl = BigDecimal.valueOf(todayData.getEfficiency().getAEfficiency()).setScale(0, RoundingMode.HALF_UP);
//        }
//        vo.getJb().setJdl(jdl);
////        vo.getJb().setOpen(currData.getDevice().getOnline(),currData.getDevice().getTotal());
//        vo.getJb().setOpenNum(currData.getDevice().getOnline());
//        vo.getJb().setTotalNum(currData.getDevice().getTotal());
//
//        vo.getJb().setOpenRatio(BigDecimal.valueOf(currData.getDevice().getRunningRatio()).setScale(0, RoundingMode.HALF_UP));
        redisCache.setCacheObject(CacheConstants.CURR_YIELD, vo);
        return redisCache.getCacheObject(CacheConstants.CURR_YIELD);
    }

    /**
     * 获取生产趋势
     *
     * @return 结果
     */
    @Override
    public List<ProdTradeVO> prodTrade() {
        List<ProdTradeVO> list = new ArrayList<>();
        IndexData id = redisCache.getCacheObject(CacheConstants.INDEX_CALC);
        YrTwinVO yrTwinVO = redisCache.getCacheObject(CacheConstants.RZ_MOCK);
        List<YrProdTradeVO> yrProdTradeVOS = yrTwinVO.getProdTrade();
        Map<String, YrProdTradeVO> yrMap = yrProdTradeVOS.stream()
                .collect(Collectors.toMap(
                        YrProdTradeVO::getTips,
                        vo -> vo,
                        (existing, replacement) -> existing
                ));
        List<WeekData> weekDataList = id.getWeekData();
        for (WeekData wd : weekDataList) {
            ProdTradeVO vo = new ProdTradeVO();
            vo.setJbLength(wd.getLength());
            vo.setJbWeight(wd.getWeight());
            LocalDate localDate = LocalDate.parse(wd.getTime());
            vo.setDate(week(localDate));
            vo.setTips(localDate.toString());
            YrProdTradeVO yr = yrMap.get(wd.getTime());
            vo.setRzLength(yr.getLine().get(0).getLength());
            vo.setRzWeight(yr.getLine().get(0).getWeight());
            list.add(vo);
        }

        return list;
    }

    /**
     * 获取能耗趋势
     * 1	WS02-D	经编车间	经编车间用电
     * 2	WS03-D-QZ	前整车间	染整线-前整车间用电
     * 3	WS03-D-YR	印染车间	染整线-印染车间用电
     * 4	WS03-D-HZ	后整车间	染整线-后整车间用电
     * 5	WS03-S-YR	印染工业水	染整线-工业水
     * 6	WS03-Q-DY	低压蒸汽	2/3低压蒸汽
     * 7	WS03-Q-ZY	中压蒸汽	中压蒸汽
     *
     * @return 结果
     */
    @Override
    public List<EnergyTradeVO> energyTrade() {
//        redisCache.setCacheObject(CacheConstants.ENERGY_TRADE, mockEnergy());
        List<EnergyTradeVO> list = new ArrayList<>();
        LocalDate end = LocalDateTime.now().minusHours(7).toLocalDate().minusDays(1);
        //一个月数据
        LocalDate start = end.minusMonths(1);
        List<TwinWorkshopCalc> wsList = wsCalcService.listByWsCodeDate(null, DateUtils.toDate(start));
        Map<Date, List<TwinWorkshopCalc>> wsMap = wsList.stream().collect(Collectors.groupingBy(TwinWorkshopCalc::getDataDate, LinkedHashMap::new, Collectors.toList()));
        for (Map.Entry<Date, List<TwinWorkshopCalc>> entry : wsMap.entrySet()) {
            EnergyTradeVO vo = new EnergyTradeVO();
            LocalDate ldt = DateUtils.toLocalDate(entry.getKey());
            List<TwinWorkshopCalc> wss = entry.getValue();
            vo.setDate(ldt.getDayOfMonth() + "");
            vo.setTips(ldt.toString());
            EnergyTradeVO.RZ rz = new EnergyTradeVO.RZ();
            rz.setElectricity(BigDecimal.ZERO);
            rz.setPrice(BigDecimal.ZERO);
            for (TwinWorkshopCalc ws : wss) {
                switch (ws.getWsCode()) {
                    case "WS02-D":
                        //经编车间用电
                        vo.getJb().setElectricity(ws.getTotalValue());
                        vo.getJb().setPrice(ws.getTotalPrice() != null ? ws.getTotalPrice() : BigDecimal.ZERO);
                        break;
                    case "WS03-D-QZ":
                        //染整线-前整车间用电
                    case "WS03-D-YR":
                        //染整线-印染车间用电
                    case "WS03-D-HZ":
                        //染整线-后整车间用电
                        if (ws.getTotalValue() != null) {
                            rz.setElectricity(rz.getElectricity().add(ws.getTotalValue()));
                        }
                        if (ws.getTotalPrice() != null) {
                            rz.setPrice(rz.getPrice().add(ws.getTotalPrice()));
                        }
                        break;
                    case "WS03-S-YR":
                        rz.setWater(ws.getTotalValue());
                        if (ws.getTotalPrice() != null) {
                            rz.setPrice(rz.getPrice().add(ws.getTotalPrice()));
                        }
                        //染整线-工业水
                        break;
                    case "WS03-Q-DY":
                        rz.setSteam(ws.getTotalValue());
                        if (ws.getTotalPrice() != null) {
                            rz.setPrice(rz.getPrice().add(ws.getTotalPrice()));
                        }
                        //染整线-工业水
                        //2/3低压蒸汽
                        break;
                    case "WS03-Q-ZY":
                        //中压蒸汽
                        break;
                    default:
                }

            }
            rz.setPrice(rz.getPrice().setScale(2, RoundingMode.HALF_UP));
            if (vo.getJb().getPrice() != null) {
                vo.getJb().setPrice(vo.getJb().getPrice().setScale(2, RoundingMode.HALF_UP));
            }
            vo.setRz(rz);
            list.add(vo);
        }
        return list;
    }


    /**
     * 获取周几
     *
     * @param date
     * @return
     */
    private String week(LocalDate date) {
        String[] weeks = {"一", "二", "三", "四", "五", "六", "日"};
        return "周" + weeks[date.getDayOfWeek().getValue() - 1];
    }

    public static void main(String[] args) {
        int day = 7;
        LocalDate end = LocalDate.now().minusDays(1);
        LocalDate start = end.minusDays(day - 1);
        do {
            System.err.println(start + "\t" + start.getDayOfWeek().getValue());
            start = start.plusDays(1);
        } while (!start.isAfter(end));
    }


    /**
     * 模拟数据
     */
    @Override
    public void mock() {
        TwinAllVO vo = new TwinAllVO();
        vo.setStock(stock());
        vo.setAvgMonth(avgMonth());
        vo.setProdTrade(prodTrade());
        vo.setEnergyTrade(energyTrade());
        redisCache.setCacheObject(CacheConstants.ALL_MOCK, vo);
    }

}
