package com.nantian.cloud.dbcapp.carbon.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nantian.cloud.dbcapp.carbon.domain.carbonDetection.*;
import com.nantian.cloud.dbcapp.carbon.mapper.CarbonEnterpriseMapper;
import com.nantian.cloud.dbcapp.carbon.service.CarbonEnterpriseService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *
 * </p>
 *
 * @author xuels
 * @since 2022/7/21
 */
@Service
public class CarbonEnterpriseServiceImpl extends ServiceImpl<CarbonEnterpriseMapper, EnterpriseDataVo> implements CarbonEnterpriseService {



    @Override
    public List<RegionEntGroupVO> entTree() {
        return baseMapper.entTree();
    }

    /**
     * 查询企业基本信息接口
     *
     * @param enterpriseName
     * @return
     */
    @Override
    public Erprise selectEnterpriseVo(String enterpriseName) {
        return baseMapper.selectEnterpriseVo(enterpriseName);
    }

    /**
     * 查询机组基本信息
     *
     * @param enterpriseName
     * @return
     */
    @Override
    public List<Machine> selectMachineVos(String enterpriseName) {
        List<Machine> machineVos = baseMapper.selectMachineVos(enterpriseName);
        for (Machine machineVo : machineVos) {
            machineVo.setFuelType(machineVo.getFuelType() + "机组");
        }
        return machineVos;
    }

    /**
     * 查询计量器具基本信息
     *
     * @return
     */
    @Override
    public List<InstrumentInfoVo> getInstrumentInfo(String enterpriseName) {
        return baseMapper.getInstrumentInfo(enterpriseName);
    }

    /**
     * 查询数据统计基本数据信息
     *
     * @param enterpriseName
     * @param year
     * @param month
     * @return
     */
    @Override
    public List<EnterpriseDataVo> getBaseAccData(String enterpriseName, String year, String month) {
        final EnterpriseDataRequest enterpriseDataRequest = new EnterpriseDataRequest();
        enterpriseDataRequest.setEntName(enterpriseName);
        enterpriseDataRequest.setYear(year);
        enterpriseDataRequest.setMonth(month);
        return baseMapper.getBaseAccData(enterpriseDataRequest);
    }

    @Override
    public Object getMechInfo(String dates, String enterpriseName, String mechNames) {
        return baseMapper.getMechInfo(dates, enterpriseName, mechNames);
    }

    @Override
    public Object getMechData(String yearMonth, String enterpriseName, String mechNames) {
        List<String> machines = baseMapper.machines(enterpriseName);
        Map<String, Object> resultMap = new HashMap<>(2);
        Calendar calendar = Calendar.getInstance();
        calendar.set(Integer.valueOf(yearMonth.substring(0, 4)), Integer.valueOf(yearMonth.substring(5, 7)), 0);
        int day = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        resultMap.put("x", new ArrayList<String>(day) {{
            for (int i = 0; i < day; ++i) {
                add(i, "" + (i + 1));
            }
        }});

        List<Map<String, Object>> valueList = new ArrayList<>(machines.size());
        resultMap.put("list", valueList);
        for (String machineName : machines) {
            List<XY> list = baseMapper.getMechData(yearMonth, enterpriseName, machineName);
            List<XY> listss = list.stream().filter(s -> s != null)
                    .collect(Collectors.toList());

            valueList.add(new HashMap<String, Object>() {{
                put("name", machineName);
                put("data", listss.stream()
                        .sequential()
                        .map(XY::getY)
                        .collect(Collectors.toList()));
                put("simulate", listss.stream()
                        .sequential()
                        .map(XY::getZ)
                        .collect(Collectors.toList()));
            }});
        }

        return resultMap;
    }

    @Override
    public Object carbonMonthSource(String enterpriseName, String yearMonth) {
        List<String> machines = baseMapper.machines(enterpriseName);
        List result = sum("月度合计", 0, baseMapper.carbonMonthSource(enterpriseName, yearMonth, machines), machines);
        machines.add(0, "日期");
        machines.add(machines.size(), "机组合计");
        return new HashMap<String, Object>() {{
            put("titles", machines);
            put("datas", result);
        }};
    }

    @Override
    public Object carbonYearSource(String enterpriseName, String year) {
        List<String> machines = baseMapper.machines(enterpriseName);
        List result = sum("年度合计", 0, baseMapper.carbonYearSource(enterpriseName, year, machines), machines);
        machines.add(0, "月度");
        machines.add(machines.size(), "机组合计");
        return new HashMap<String, Object>() {{
            put("titles", machines);
            put("datas", result);
        }};
    }

    @Override
    public Object distribute(String enterpriseName, String year) {
        List<String> machines = baseMapper.machines(enterpriseName);
        List result = sum("年度合计", 0, baseMapper.distribute(enterpriseName, year, machines), machines);
        machines.add(0, "月度");
        machines.add(machines.size(), "机组合计");
        return new HashMap<String, Object>() {{
            put("titles", machines);
            put("datas", result);
        }};
    }

    @Override
    public Object distributeDetail(String enterpriseName, String machineName, String year, Integer month) {
        return baseMapper.distributeDetail(enterpriseName, machineName, year, month);
    }

    @Override
    public Object distributeTotal(String enterpriseName, String year) {
        List<DistributeMonth> list = baseMapper.distributeTotal(enterpriseName, year);
        DistributeMonth conclusion = new DistributeMonth();
        conclusion.setMonth("年度合计");
        conclusion.setBlowoff(BigDecimal.ZERO);
        conclusion.setTotal(BigDecimal.ZERO);
        conclusion.setDistribute(BigDecimal.ZERO);
        for (DistributeMonth distributeMonth : list) {
            if (distributeMonth.getBlowoff() != null) {
                conclusion.setBlowoff(conclusion.getBlowoff().add(distributeMonth.getBlowoff()));
            }
            if (distributeMonth.getTotal() != null) {
                conclusion.setTotal(conclusion.getTotal().add(distributeMonth.getTotal()));
            }
            if (distributeMonth.getDistribute() != null) {
                conclusion.setDistribute(conclusion.getDistribute().add(distributeMonth.getDistribute()));
            }
        }
        list.add(0, conclusion);
        return list;
    }

    private List<Map> sum(String name, Integer position, List<Map> list, List<String> machines) {
        Map<String, Object> conclusion = new HashMap<>();
        conclusion.put("NAME", name);
        // 空列表处理
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<Map>(1) {{
                add(conclusion);
            }};
        }

        // 计算总和
        for (Object objKey : list.get(0).keySet()) {
            String key = String.valueOf(objKey);
            // 命名不计算
            if ("NAME".equals(key)) {
                continue;
            }
            BigDecimal sum = new BigDecimal(0);
            Boolean sumable = true, hasOneNum = false;
            for (Map map : list) {
                String value = map.get(key) == null ? "" : map.get(key).toString();
                // 为空或者null无法说明当前列是什么类型的列，判断下一行
                if (value.equals("") || value.equals("null")) {
                    continue;
                }
                // 有值但又不是数字，确定该列不是累计列，跳出
                if (!NumberUtils.isNumber(map.get(key).toString())) {
                    // 记录该列为非数值列
                    sumable = false;
                    break;
                }
                // 累计
                sum = sum.add(new BigDecimal(map.get(key).toString()));
                // 记录该列至少有一个值可用于算总和
                hasOneNum = true;
            }
            // 非数值列设置默认值然后返回
            if (!sumable) {
                conclusion.put(key, "-");
                continue;
            }
            // 数值列，但是没有一行数据用于加和
            if (!hasOneNum) {
                conclusion.put(key, 0);
                continue;
            }
            // 普通累加
            sum = sum.setScale(2, BigDecimal.ROUND_HALF_UP);
            conclusion.put(key, sum);
        }
        if (position == null) {
            list.add(conclusion);
        }
        else {
            list.add(position, conclusion);
        }

        // 不改myabtis配置，map返回值为null的时候是没有字段的，这里添加
        list.forEach(map -> {
            for (int i = 0; i < machines.size(); ++i) {
                if (!map.containsKey("V" + i)) {
                    map.put("V" + i, "");
                }
            }
        });
        return list;
    }

}
