package cn.cecep.talroad.service.impl;

import cn.cecep.talroad.common.core.utils.DateUtils;
import cn.cecep.talroad.common.core.utils.StringUtils;
import cn.cecep.talroad.common.core.web.domain.AjaxResults;
import cn.cecep.talroad.domain.BaseControlConcentStandards;
import cn.cecep.talroad.domain.BaseRegionalControlObjectives;
import cn.cecep.talroad.domain.PcFactoryPollutant;
import cn.cecep.talroad.domain.PcLabelFactory;
import cn.cecep.talroad.mapper.BaseControlConcentStandardsMapper;
import cn.cecep.talroad.mapper.PcFactoryPollutantMapper;
import cn.cecep.talroad.mapper.SEnvGasMonRealMapper;
import cn.cecep.talroad.service.BaseControlConcentStandardsService;
import cn.cecep.talroad.service.BaseRegionalControlObjectivesService;
import cn.cecep.talroad.vo.BaseControlConcentStandardsVo;
import cn.cecep.talroad.vo.SEnvGasMonRealVo;
import cn.cecep.talroad.vo.query.BaseControlConcentStandardsQuery;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.jsonwebtoken.lang.Collections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@Service
public class BaseControlConcentStandardsServiceImpl implements BaseControlConcentStandardsService{

    @Resource
    private BaseControlConcentStandardsMapper baseControlConcentStandardsMapper;

    @Autowired
    private SEnvGasMonRealMapper gasMonRealMapper;

    @Autowired
    private BaseRegionalControlObjectivesService baseRegionalControlObjectivesService;
    @Autowired
    private PcFactoryPollutantMapper pcFactoryPollutantMapper;

    @Override
    public AjaxResults<IPage<BaseControlConcentStandardsVo>> selectList(BaseControlConcentStandardsQuery query) {
        Page<BaseRegionalControlObjectives> page = new Page<>(query.getPageNum(), query.getPageSize());
        IPage<BaseControlConcentStandardsVo> result = baseControlConcentStandardsMapper.selectListPage(page, query);
        return  AjaxResults.success(result);
    }

    @Override
    public int insert(BaseControlConcentStandards record) {
        return baseControlConcentStandardsMapper.insert(record);
    }

    @Override
    public int insertSelective(BaseControlConcentStandards record) {
        return baseControlConcentStandardsMapper.insertSelective(record);
    }

    @Override
    public BaseControlConcentStandards selectByPrimaryKey(String id) {
        return baseControlConcentStandardsMapper.selectByPrimaryKey(id);
    }

    @Override
    public int updateByPrimaryKeySelective(BaseControlConcentStandards record) {
        return baseControlConcentStandardsMapper.updateByPrimaryKeySelective(record);
    }

    @Override
    public int updateByPrimaryKey(BaseControlConcentStandards record) {
        return baseControlConcentStandardsMapper.updateByPrimaryKey(record);
    }

    @Override
    public int updateBatchSelective(List<BaseControlConcentStandards> list) {
        return baseControlConcentStandardsMapper.updateBatchSelective(list);
    }

    @Override
    public int batchInsert(List<BaseControlConcentStandards> list) {
        return baseControlConcentStandardsMapper.batchInsert(list);
    }

    /**
     * 更新建议排放量小时均值
     */
    public void updateAdviceEmissionAvg() {
        // 查询纳入计算的数据
        List<BaseControlConcentStandards> standards = baseControlConcentStandardsMapper.selectList(new QueryWrapper<BaseControlConcentStandards>()
                .eq("include_calculations", "1"));
        if (standards.isEmpty()) {
            return;
        }
        Date date = new Date();
        String endTime = DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", DateUtils.addHours(date, -1));
        String startTime = DateUtils.parseDateToStr("yyyy-MM-dd HH", DateUtils.addHours(date, -720));

        /*
            获取前30天指定监测点废气小时排放量的均值
            需要去掉在线监测系统白名单表里的ps_whitelist_reason字段和停产表的dcstype时段的排放量算均值
         */
        Set<String> outletIds = standards.stream().map(o -> o.getOutletId()).collect(Collectors.toSet());
        List<SEnvGasMonRealVo.OxygenEmissionAvg> emissionVoList = gasMonRealMapper.selectEmissionAvg(startTime, endTime, outletIds);
        Map<String, SEnvGasMonRealVo.OxygenEmissionAvg> outletEmissionAvgMap = emissionVoList.stream().collect(Collectors.toMap(o -> o.getOutletId(), o -> o));

        for (BaseControlConcentStandards standard : standards) {
            // 监测点前720小时的平均值，去掉了白名单和停产记录后算的均值
            SEnvGasMonRealVo.OxygenEmissionAvg beforeAvgHourData = outletEmissionAvgMap.get(standard.getOutletId());

            /*
                设置建议目标排放量，需求如下：
                用前30天废气小时排放量的均值作为要用的废气小时排放量
                需要去掉在线监测系统白名单表里的ps_whitelist_reason字段和停产表的dcstype时段的排放量算均值
                目标排放量=管控浓度设置模块设置的浓度乘以刚才算出的废气小时排放量均值除以1000000
             */
            if (beforeAvgHourData != null && beforeAvgHourData.getOxygenEmissionAvg() != null && standard.getControlStandard() != null) {
                standard.setAdviceEmissionAvg(standard.getControlStandard().multiply(beforeAvgHourData.getOxygenEmissionAvg())
                        .divide(BigDecimal.valueOf(1000000), 6, BigDecimal.ROUND_HALF_UP));
            }
        }

        List<List<BaseControlConcentStandards>> partition = ListUtil.partition(standards, 2000);
        for (List<BaseControlConcentStandards> list : partition) {
            baseControlConcentStandardsMapper.updateAdviceEmissionAvg(list);
        }

        // 插入或更新区域管控目标，并根据监测点管控浓度建议排放量更新区域的建议排放量
        baseRegionalControlObjectivesService.saveOrUpdate();

    }

    @Override
    @Transactional
    public void importData(List<BaseControlConcentStandards> datas) {
        if(Collections.isEmpty(datas)){
            return;
        }
        int quantityPerTime=2500;
        int limit=(datas.size()+quantityPerTime-1)/quantityPerTime;
        //分组
        List<List<BaseControlConcentStandards>> dataList = Stream.iterate(0, n -> n + 1).limit(limit).parallel().map(a ->
                datas.stream().skip(a * quantityPerTime).limit(quantityPerTime).parallel().collect(Collectors.toList())).collect(Collectors.toList());
        //每组 quantityPerTime 条批次
        for (List<BaseControlConcentStandards> data : dataList) {
            List<String> factoryIds =new ArrayList<>();
            List<String> outletIds =new ArrayList<>();
            List<String> pollutantCodes =new ArrayList<>();
            data.forEach(d->{
                        if(!StringUtils.isAnyEmpty(d.getFactoryId(),d.getOutletId(),d.getPollutantType())){
                            d.setFactoryId(d.getFactoryId().replace("\t",""));
                            factoryIds.add(d.getFactoryId());
                            outletIds.add(d.getOutletId());
                            pollutantCodes.add(d.getPollutantType());
                        }
                    }
            );
            QueryWrapper<BaseControlConcentStandards> wrapper= Wrappers.query();
            wrapper.in("factory_id",factoryIds);
            wrapper.in("outlet_id",outletIds);
            wrapper.in("pollutant_type",pollutantCodes);
            List<BaseControlConcentStandards> baseControlConcentStandards = baseControlConcentStandardsMapper.selectList(wrapper);
            Map<String, BaseControlConcentStandards> map = baseControlConcentStandards.stream().collect(Collectors.toMap(bcs ->
                    (bcs.getFactoryId() + bcs.getOutletId()+bcs.getPollutantType()), bcs -> bcs));
            List<BaseControlConcentStandards> updates=new ArrayList<>();
            List<BaseControlConcentStandards> addlist=new ArrayList<>();
            data.forEach(d->{
                if(map.containsKey(d.getFactoryId()+d.getOutletId()+d.getPollutantType())){
                    BaseControlConcentStandards baseControlConcentStandards1 = map.get(d.getFactoryId() + d.getOutletId() + d.getPollutantType());
                    d.setId(baseControlConcentStandards1.getId());
                    updates.add(d);
                }else {
                    d.setId(UUID.randomUUID().toString());
                    List<BaseControlConcentStandards> collect = addlist.stream().filter(a ->
                            d.getFactoryId().equals(a.getFactoryId()) && d.getOutletId().equals(a.getOutletId()) && d.getPollutantType().equals(a.getPollutantType())).collect(Collectors.toList());
                    addlist.removeAll(collect);
                    addlist.add(d);
                }
            });
            if(!Collections.isEmpty(updates)){
                baseControlConcentStandardsMapper.updateBatchSelective(updates);
            }
            if(!Collections.isEmpty(addlist)){
                baseControlConcentStandardsMapper.batchInsert(addlist);
            }
        }

    }

    @Override
    public Integer addPollutant(String code, Integer type) {
        baseControlConcentStandardsMapper.deletePollutant(code,type);
      List<PcFactoryPollutant> maps= baseControlConcentStandardsMapper.addPollutant(code,type);
        maps.forEach(item->{
            item.setId(UUID.randomUUID().toString().replace("-", ""));
            item.setPollutantId(code);
            item.setIsStatus("1");
        });
        if(CollectionUtil.isNotEmpty(maps)){
            List<List<PcFactoryPollutant>> partition = ListUtil.partition(maps, 2000);
            partition.forEach(i->{
                pcFactoryPollutantMapper.batchUpdateValue(i);
            });
        }
        return null;
    }
}
