package com.jjt.ws.service.impl;

import com.jjt.calc.domain.TwinCalcHourEnergy;
import com.jjt.calc.service.ITwinCalcHourEnergyService;
import com.jjt.common.utils.DateUtils;
import com.jjt.common.utils.StringUtils;
import com.jjt.elec.domain.ElecPrice;
import com.jjt.elec.service.IElecPriceService;
import com.jjt.ws.domain.TwinWorkshop;
import com.jjt.ws.domain.TwinWorkshopCalc;
import com.jjt.ws.domain.TwinWorkshopEnergy;
import com.jjt.ws.mapper.TwinWorkshopCalcMapper;
import com.jjt.ws.service.ITwinRzCalcMonthService;
import com.jjt.ws.service.ITwinWorkshopCalcService;
import com.jjt.ws.service.ITwinWorkshopService;
import com.jjt.ws.vo.MonthCalcVO;
import javafx.util.Pair;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 能源统计Service业务层处理
 *
 * @author wukai
 * @date 2025-01-17
 */
@Service
public class TwinWorkshopCalcServiceImpl implements ITwinWorkshopCalcService {
    @Resource
    private TwinWorkshopCalcMapper twinWorkshopCalcMapper;
    @Resource
    private ITwinCalcHourEnergyService energyService;
    @Resource
    private SqlSessionFactory factory;
    @Resource
    private ITwinWorkshopService wsService;
    @Resource
    private IElecPriceService elecPriceService;
    @Resource
    private ITwinRzCalcMonthService rzCalcMonthService;

    /**
     * 查询能源统计
     *
     * @param calcId 能源统计主键
     * @return 能源统计
     */
    @Override
    public TwinWorkshopCalc selectTwinWorkshopCalcByCalcId(Long calcId) {
        return twinWorkshopCalcMapper.selectTwinWorkshopCalcByCalcId(calcId);
    }

    /**
     * 查询能源统计列表
     *
     * @param twinWorkshopCalc 能源统计
     * @return 能源统计
     */
    @Override
    public List<TwinWorkshopCalc> selectTwinWorkshopCalcList(TwinWorkshopCalc twinWorkshopCalc) {
        return twinWorkshopCalcMapper.selectTwinWorkshopCalcList(twinWorkshopCalc);
    }

    /**
     * 新增能源统计
     *
     * @param twinWorkshopCalc 能源统计
     * @return 结果
     */
    @Override
    public int insertTwinWorkshopCalc(TwinWorkshopCalc twinWorkshopCalc) {
        return twinWorkshopCalcMapper.insertTwinWorkshopCalc(twinWorkshopCalc);
    }

    /**
     * 修改能源统计
     *
     * @param twinWorkshopCalc 能源统计
     * @return 结果
     */
    @Override
    public int updateTwinWorkshopCalc(TwinWorkshopCalc twinWorkshopCalc) {
        return twinWorkshopCalcMapper.updateTwinWorkshopCalc(twinWorkshopCalc);
    }

    /**
     * 批量删除能源统计
     *
     * @param calcIds 需要删除的能源统计主键
     * @return 结果
     */
    @Override
    public int deleteTwinWorkshopCalcByCalcIds(Long[] calcIds) {
        return twinWorkshopCalcMapper.deleteTwinWorkshopCalcByCalcIds(calcIds);
    }

    /**
     * 删除能源统计信息
     *
     * @param calcId 能源统计主键
     * @return 结果
     */
    @Override
    public int deleteTwinWorkshopCalcByCalcId(Long calcId) {
        return twinWorkshopCalcMapper.deleteTwinWorkshopCalcByCalcId(calcId);
    }

    /**
     * 能源日统计
     *
     * @param localDate 日期
     * @return 结果
     */
    @Override
    public int calc(LocalDate localDate) {
        Date date = DateUtils.toDate(localDate);
        //先删除
        twinWorkshopCalcMapper.deleteTwinWorkshopCalcByDate(date);
        List<TwinWorkshopCalc> calcList = new ArrayList<>();
        List<TwinWorkshop> wsList = wsService.selectTwinWorkshopList(new TwinWorkshop());
        //存储能源ID和车间ID关系
        Map<Long, TwinWorkshop> wsMap = new HashMap<>(16);
        //ID-车间
        Map<Long, TwinWorkshop> wsVoMap = new HashMap<>(16);
        wsList.forEach(ws -> {
            List<TwinWorkshopEnergy> list = wsService.selectTwinWorkshopByWsId(ws.getWsId()).getTwinWorkshopEnergyList();
            list.forEach(o -> wsMap.put(o.getEnergyId(), ws));
            wsVoMap.put(ws.getWsId(), ws);
        });
        //获取统计数据
        List<TwinCalcHourEnergy> energyList = energyService.selectTwinEmpCalcListByDate(date);
        Map<Integer, Pair<String, BigDecimal>> elecPrice = elecPriceService.getPrice(localDate);
        for (TwinCalcHourEnergy obj : energyList) {
            obj.setTeam();
            TwinWorkshop ws = wsMap.get(obj.getEnergyId());
            if (ws == null) {
                continue;
            }
            obj.setWsId(ws.getWsId());
            switch (ws.getWsCode()) {
                case "WS02-D":
                case "WS03-D-QZ":
                case "WS03-D-HZ":
                case "WS03-D-YR":
                    //电
                    Pair<String, BigDecimal> pair = elecPrice.get(obj.getHour());
                    if (pair != null) {
                        obj.calcPrice(pair.getValue());
                        obj.setType(pair.getKey() + "," + pair.getValue());
                    }
                    break;
                case "WS03-S-YR":
                    //水
                    BigDecimal waterPrice = elecPrice.get(100).getValue();
                    obj.calcPrice(waterPrice);
                    break;
                case "WS03-Q-DY":
                    //低压蒸汽
                    BigDecimal lowPrice = elecPrice.get(210).getValue();
                    obj.calcPrice(lowPrice);
                    break;
                case "WS03-Q-ZY":
                    //中亚蒸汽
                    BigDecimal midPrice = elecPrice.get(220).getValue();
                    obj.calcPrice(midPrice);
                    break;
                default:
            }
        }
        //先按ID分组
        Map<Long, List<TwinCalcHourEnergy>> calcMap = energyList.stream().filter(o -> o.getWsId() != null).collect(Collectors.groupingBy(TwinCalcHourEnergy::getWsId, LinkedHashMap::new, Collectors.toList()));
        for (Long wsId : calcMap.keySet()) {
            //按班组统计用量和价格
            Map<String, TwinWorkshopCalc> resultMap = calcMap.get(wsId).stream().filter(o -> o.getPrice() != null).collect(Collectors.groupingBy(TwinCalcHourEnergy::getTeam,
                    Collectors.collectingAndThen(
                            Collectors.toList(),
                            list -> {
                                BigDecimal v = list.stream().map(TwinCalcHourEnergy::getDataValue).reduce(BigDecimal.ZERO, BigDecimal::add);
                                BigDecimal p = list.stream().map(TwinCalcHourEnergy::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
                                TwinWorkshopCalc c = new TwinWorkshopCalc();
                                c.setTotalPrice(p);
                                c.setTotalValue(v);
                                return c;
                            }
                    )));


            TwinWorkshopCalc calc = new TwinWorkshopCalc();
            calc.setWsId(wsId);
            calc.setWsCode(wsVoMap.get(wsId).getWsCode());
            calc.setDataDate(date);
            BigDecimal totalA = BigDecimal.ZERO;
            BigDecimal totalB = BigDecimal.ZERO;
            BigDecimal priceA = BigDecimal.ZERO;
            BigDecimal priceB = BigDecimal.ZERO;
            if (resultMap.get("A") != null) {
                totalA = resultMap.get("A").getTotalValue();
                priceA = resultMap.get("A").getTotalPrice();
            }
            if (resultMap.get("B") != null) {
                totalB = resultMap.get("B").getTotalValue();
                priceB = resultMap.get("B").getTotalPrice();
            }
            calc.setValue(totalA, totalB);
            calc.setPrice(priceA, priceB);

            //按用电类型统计用量和价格
            Map<String, TwinWorkshopCalc> dMap = calcMap.get(wsId).stream().filter(o -> StringUtils.isNotEmpty(o.getType())).collect(Collectors.groupingBy(TwinCalcHourEnergy::getType,
                    Collectors.collectingAndThen(
                            Collectors.toList(),
                            list -> {
                                BigDecimal v = list.stream().map(TwinCalcHourEnergy::getDataValue).reduce(BigDecimal.ZERO, BigDecimal::add);
                                BigDecimal p = list.stream().map(TwinCalcHourEnergy::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
                                TwinWorkshopCalc c = new TwinWorkshopCalc();
                                c.setTotalPrice(p);
                                c.setTotalValue(v);
                                return c;
                            }
                    )));
            if (dMap != null) {
                for (String type : dMap.keySet()) {
                    String[] tmp = type.split(",");
                    TwinWorkshopCalc c = dMap.get(type);
                    String tt = tmp[0];
                    BigDecimal price = new BigDecimal(tmp[1]);
                    switch (tt) {
                        case "peak":
                            calc.setPeakUPrice(price);
                            calc.setPeakTPrice(c.getTotalPrice());
                            calc.setPeakValue(c.getTotalValue());
                            break;
                        case "flat":
                            calc.setFlatUPrice(price);
                            calc.setFlatTPrice(c.getTotalPrice());
                            calc.setFlatValue(c.getTotalValue());
                            break;
                        case "valley":
                            calc.setValleyUPrice(price);
                            calc.setValleyTPrice(c.getTotalPrice());
                            calc.setValleyValue(c.getTotalValue());
                            break;
                        case "superPeak":
                            calc.setSuperPeakUPrice(price);
                            calc.setSuperPeakTPrice(c.getTotalPrice());
                            calc.setSuperPeakValue(c.getTotalValue());
                            break;
                        default:
                    }
                }
            }

            calcList.add(calc);

        }
        if (calcList.size() > 0) {
            try (SqlSession sqlSession = factory.openSession(ExecutorType.BATCH, false)) {
                TwinWorkshopCalcMapper mapper = sqlSession.getMapper(TwinWorkshopCalcMapper.class);
                calcList.forEach(mapper::insertTwinWorkshopCalc);
                sqlSession.commit();
            }
            rzCalcMonthService.calc(date, calcList);
        }
        return 1;
    }

    /**
     * 根据日期查询
     *
     * @param wsId wsid
     * @param date 日期
     * @return 结果
     */
    @Override
    public List<TwinWorkshopCalc> selectTwinWorkshopCalcListByDate(Long wsId, Date date) {
        TwinWorkshopCalc search = new TwinWorkshopCalc();
        search.setWsId(wsId);
        search.setDataDate(date);
        return selectTwinWorkshopCalcList(search);
    }

    /**
     * 按月查询
     *
     * @param wsId  wsid
     * @param month 月份
     * @return 结果
     */
    @Override
    public List<TwinWorkshopCalc> selectTwinWorkshopCalcListByMonth(Long wsId, String month) {
        return twinWorkshopCalcMapper.selectTwinWorkshopCalcListByMonth(wsId, month);
    }

    /**
     * 按车间查询指定时间及之后的用量
     *
     * @param wsCode 车间编码
     * @param date   时间
     * @return 结果
     */
    @Override
    public List<TwinWorkshopCalc> listByWsCodeDate(String wsCode, Date date) {
        return twinWorkshopCalcMapper.listByWsCodeDate(wsCode, date);
    }

    /**
     * 染整线月统计
     *
     * @param twinWorkshopCalc 查询条件
     * @return 结果
     */
    @Override
    public List<MonthCalcVO> calcYr(TwinWorkshopCalc twinWorkshopCalc) {
        String para = (String) twinWorkshopCalc.getParams().get("month");
        int year = Integer.parseInt(para.split("-")[0]);
        int month = Integer.parseInt(para.split("-")[1]);
        ElecPrice elecPrice = elecPriceService.selectElecPriceByMonth(year, month);
        List<MonthCalcVO> result = new ArrayList<>();
        List<TwinWorkshopCalc> list = selectTwinWorkshopCalcList(twinWorkshopCalc);
        list.sort(Comparator.comparing(TwinWorkshopCalc::getDataDate));
        //按日期分组
        Map<Date, List<TwinWorkshopCalc>> allMap = list.stream().collect(Collectors.groupingBy(TwinWorkshopCalc::getDataDate, LinkedHashMap::new, Collectors.toList()));
        for (Date date : allMap.keySet()) {
            List<TwinWorkshopCalc> todList = allMap.get(date);
            MonthCalcVO vo = new MonthCalcVO();
            vo.setDate(date);
            vo.setElecPrice(elecPrice);
            for (TwinWorkshopCalc calc : todList) {
                switch (calc.getWsCode()) {
                    case "WS03-D-QZ":
                        setWorkshopData(vo.getD().getQz(), calc);
                        break;
                    case "WS03-D-HZ":
                        setWorkshopData(vo.getD().getHz(), calc);
                        break;
                    case "WS03-D-YR":
                        setWorkshopData(vo.getD().getYr(), calc);
                        break;
                    case "WS03-S-YR":
                        MonthCalcVO.S s = vo.getS();
                        s.setPrice(calc.getTotalPrice());
                        s.setUse(calc.getTotalValue());
                        break;
                    case "WS03-Q-DY":
                        setQuarterData(vo.getQ(), calc, BigDecimal.valueOf(257), "low");
                        break;
                    case "WS03-Q-ZY":
                        setQuarterData(vo.getQ(), calc, BigDecimal.valueOf(223), "mid");
                        break;
                    default:
                }

            }
            vo.setPrice();
            result.add(vo);
        }
        return result;
    }

    private void setWorkshopData(MonthCalcVO.D.DD dd, TwinWorkshopCalc calc) {
        dd.setUse(calc.getTotalValue());
        dd.setPrice(calc.getTotalPrice());
        dd.setFPrice(calc.getPeakUPrice());
        dd.setFUse(calc.getPeakValue());
        dd.setPPrice(calc.getFlatUPrice());
        dd.setPUse(calc.getFlatValue());
        dd.setGPrice(calc.getValleyUPrice());
        dd.setGUse(calc.getValleyValue());
        dd.setJfPrice(calc.getSuperPeakUPrice());
        dd.setJfUse(calc.getSuperPeakValue());
    }

    private void setQuarterData(MonthCalcVO.Q q, TwinWorkshopCalc calc, BigDecimal unitPrice, String type) {
        switch (type) {
            case "low":
                q.setLowPrice(calc.getTotalPrice());
                q.setLowUse(calc.getTotalValue());
                q.setLowUnitPrice(unitPrice);
                break;
            case "mid":
                q.setMidPrice(calc.getTotalPrice());
                q.setMidUse(calc.getTotalValue());
                q.setMidUnitPrice(unitPrice);
                break;
            default:
        }
    }
}
