package com.njcn.device.pms.service.majornetwork.impl;

import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njcn.common.pojo.enums.common.DataStateEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.pojo.param.StatisticsBizBaseParam;
import com.njcn.device.biz.pojo.po.Overlimit;
import com.njcn.device.biz.utils.COverlimitUtil;
import com.njcn.device.pms.enums.PmsDeviceResponseEnum;
import com.njcn.device.pms.mapper.majornetwork.OverlimitMapper;
import com.njcn.device.pms.mapper.majornetwork.PowerDistributionareaMapper;
import com.njcn.device.pms.pojo.excel.PowerDistributionAreaExcel;
import com.njcn.device.pms.pojo.excel.PowerGenerationUserExcel;
import com.njcn.device.pms.pojo.param.PowerDistributionareaParam;
import com.njcn.device.pms.pojo.param.TaiZhangParam;
import com.njcn.device.pms.pojo.po.GeneratrixWire;
import com.njcn.device.pms.pojo.po.PowerDistributionarea;
import com.njcn.device.pms.pojo.po.PowerGenerationUser;
import com.njcn.device.pms.pojo.po.StatationStat;
import com.njcn.device.pms.pojo.vo.PVCapacity;
import com.njcn.device.pms.service.majornetwork.IDistributionMonitorService;
import com.njcn.device.pms.service.majornetwork.IGeneratrixWireService;
import com.njcn.device.pms.service.majornetwork.IPowerDistributionareaService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.device.pms.service.majornetwork.IStatationStatService;
import com.njcn.device.pms.utils.PubUtil;
import com.njcn.event.pojo.vo.DeptLevelVO;
import com.njcn.event.utils.DeptUtil;
import com.njcn.poi.excel.ExcelUtil;
import com.njcn.poi.excel.PullDown;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.enums.DicDataTypeEnum;
import com.njcn.system.pojo.po.DictData;
import com.njcn.user.api.DeptFeignClient;
import com.njcn.user.pojo.dto.DeptDTO;
import com.njcn.user.pojo.po.Dept;
import com.njcn.user.pojo.vo.PvTerminalTreeVO;
import com.njcn.web.factory.PageFactory;
import com.njcn.web.pojo.param.BaseParam;
import com.njcn.web.utils.RequestUtil;
import com.njcn.web.utils.WebUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  台区信息
 * </p>
 *
 * @author hongawen
 * @since 2022-10-14
 */
@Service
@RequiredArgsConstructor
public class PowerDistributionareaServiceImpl extends ServiceImpl<PowerDistributionareaMapper, PowerDistributionarea> implements IPowerDistributionareaService {

    private final DeptFeignClient deptFeignClient;
    private final DicDataFeignClient dicDataFeignClient;

    private final IStatationStatService iStatationStatService;
    private final IDistributionMonitorService iDistributionMonitorService;
    private final IStatationStatService statationStatService;
    private final IGeneratrixWireService generatrixWireService;


    @Override
    public Page<PowerDistributionarea> getList(TaiZhangParam baseParam) {
        List<String> deptInfo = deptFeignClient.getDepSonSelfCodetByDeptId(baseParam.getOrgId()).getData();
        LambdaQueryWrapper<PowerDistributionarea> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(PowerDistributionarea::getStatus,DataStateEnum.ENABLE.getCode())
                .in(CollUtil.isNotEmpty(deptInfo),PowerDistributionarea::getOrgId,deptInfo)
        .and(StrUtil.isNotBlank(baseParam.getSearchValue()),
                i->i.like(PowerDistributionarea::getName,baseParam.getSearchValue())
                .or()
                .like(PowerDistributionarea::getPowerrName,baseParam.getSearchValue())
                        .or()
                        .like(PowerDistributionarea::getLineName,baseParam.getSearchValue())

                .or()
                .like(PowerDistributionarea::getOrgName,baseParam.getSearchValue())).orderByDesc(PowerDistributionarea::getCreateTime);

        //初始化分页数据
        return this.page(new Page<>(PageFactory.getPageNum(baseParam), PageFactory.getPageSize(baseParam)), lambdaQueryWrapper);
    }

    @Override
    public List<PowerDistributionarea> getPowerDistributionList(PowerDistributionareaParam powerDistributionareaParam) {
        LambdaQueryWrapper<PowerDistributionarea> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if(StrUtil.isNotBlank(powerDistributionareaParam.getOrgId())){
            List<String> deptIds = deptFeignClient.getDepSonSelfCodetByDeptId(powerDistributionareaParam.getOrgId()).getData();
            lambdaQueryWrapper.in(PowerDistributionarea::getOrgId,deptIds).eq(PowerDistributionarea::getStatus,DataStateEnum.ENABLE.getCode());
        }

        if(StrUtil.isNotBlank(powerDistributionareaParam.getLineId())){
            lambdaQueryWrapper.eq(PowerDistributionarea::getLineId,powerDistributionareaParam.getLineId());
        }
        if(StrUtil.isNotBlank(powerDistributionareaParam.getName())){
            lambdaQueryWrapper.like(PowerDistributionarea::getName,powerDistributionareaParam.getName())
            .or().like(PowerDistributionarea::getOrgName,powerDistributionareaParam.getName());
        }

        lambdaQueryWrapper.select(PowerDistributionarea::getId,PowerDistributionarea::getName,PowerDistributionarea::getOrgId,PowerDistributionarea::getOrgName,PowerDistributionarea::getPowerStationId).last(" limit 1000")
       ;

        lambdaQueryWrapper.orderByDesc(PowerDistributionarea::getCreateTime);
        return this.list(lambdaQueryWrapper);
    }



    /**
     * 根据id查询
     * @author hany
     * @date 2022/10/26
     */
    @Override
    public PowerDistributionarea getDistrictById(String id) {
        return this.getById(id);
    }

    /**
     * 新增台区信息
     * @author hany
     * @date 2022/10/26
     */
    @Override
    public boolean add(PowerDistributionareaParam newParam) {
        LambdaQueryWrapper<PowerDistributionarea> che = new LambdaQueryWrapper<>();
        che.eq(PowerDistributionarea::getId,newParam.getId());
        int count = this.count(che);
        if(count>0){
            throw new BusinessException(PmsDeviceResponseEnum.POWER_CODE_SAME);
        }
        checkName(newParam,true);

        Dept dept = deptFeignClient.getDeptByCode(newParam.getOrgId()).getData();
        if(Objects.isNull(dept)){
            throw new BusinessException(PmsDeviceResponseEnum.ORG_ITEM_EMPTY);
        }

        Dept opDept = deptFeignClient.getDeptByCode(newParam.getOperationId()).getData();
        if(Objects.isNull(opDept)){
            throw new BusinessException(PmsDeviceResponseEnum.Operation_ITEM_EMPTY);
        }

        StatationStat statationStat = iStatationStatService.getStatationStatById(newParam.getPowerStationId());
        if(Objects.isNull(statationStat)){
            throw new BusinessException(PmsDeviceResponseEnum.NO_STATION);
        }


        PowerDistributionarea powerDistributionarea = new PowerDistributionarea();
        BeanUtils.copyProperties(newParam,powerDistributionarea);
        //设为正常状态
        powerDistributionarea.setStatus(DataStateEnum.ENABLE.getCode());
        this.save(powerDistributionarea);

        return true;
    }

    /**
     * 修改台区信息
     * @author hany
     * @date 2022/10/26
     */
    @Override
    public boolean update(PowerDistributionareaParam updateParam) {
        PowerDistributionarea powerDistributionarea = this.getById(updateParam.getId());
        if(Objects.isNull(powerDistributionarea)){
            throw new BusinessException(PmsDeviceResponseEnum.POWER_DIS_NOT_FIND);
        }
        checkName(updateParam,false);
        BeanUtils.copyProperties(updateParam,powerDistributionarea);
        return this.updateById(powerDistributionarea);
    }

    /**
     * 删除
     * @param ids
     */
    @Override
    @Transactional(rollbackFor=RuntimeException.class)
    public boolean delete(List<String> ids) {
        iDistributionMonitorService.removeByIds(ids);
        return this.removeByIds(ids);
    }

    @Override
    public PVCapacity getPVCapacity(StatisticsBizBaseParam param) {
        List<DeptDTO> data = deptFeignClient.getDeptDescendantIndexes(param.getId(), WebUtil.filterDeptType()).getData();
        List<String> deptCode = data.stream().map(DeptDTO::getCode).collect(Collectors.toList());
        return this.baseMapper.selectPVCapacity(deptCode);
    }

    @Override
    public PVCapacity.PVCapacityCount getPVPermeability(StatisticsBizBaseParam param) {
        List<DeptDTO> data = deptFeignClient.getDeptDescendantIndexes(param.getId(), WebUtil.filterDeptType()).getData();
        List<String> deptCode = data.stream().map(DeptDTO::getCode).collect(Collectors.toList());
        return this.baseMapper.selectPPVPermeability(deptCode);
    }

    @Override
    public List<PVCapacity.Absorptive> getAbsorptiveCapacity(StatisticsBizBaseParam param) {
        List<PVCapacity.Absorptive> info=new ArrayList<>();
        List<DeptDTO> data = deptFeignClient.getDeptDescendantIndexes(param.getId(), WebUtil.filterDeptType()).getData();
        List<String> deptCode = data.stream().map(DeptDTO::getCode).collect(Collectors.toList());
        //获取所有的数据信息
        List<PVCapacity.Absorptive> list= this.baseMapper.selectAbsorptiveCapacity(deptCode);
        List<DeptLevelVO> deptLevelVOList = DeptUtil.getDeptLevelVOList(data, param.getId());
        PVCapacity.Absorptive absorptive;
        for (DeptLevelVO deptLevelVO : deptLevelVOList) {
            absorptive=new PVCapacity.Absorptive();
            absorptive.setOrg(deptLevelVO.getName());
            if(CollUtil.isNotEmpty(list)){
                List<String>  subsetDept= deptLevelVO.getDeptList().stream().map(DeptLevelVO::getCode).collect(Collectors.toList());
                List<PVCapacity.Absorptive> collect = list.stream().filter(x -> x.getOrg().equals(deptLevelVO.getCode()) ||
                        subsetDept.contains(x.getOrg())).collect(Collectors.toList());
                absorptive.setCapacity(NumberUtil.round(collect.stream().mapToDouble(PVCapacity.Absorptive::getCapacity).sum(),2).doubleValue());
                absorptive.setConsumption(NumberUtil.round(collect.stream().mapToDouble(PVCapacity.Absorptive::getConsumption).sum(),2).doubleValue());
            }else{
                absorptive.setCapacity(0.0);
                absorptive.setConsumption(0.0);
            }
            info.add(absorptive);
        }
        return info;
    }

    @Override
    public void export() {
        ExportParams exportParams = new ExportParams("台区台账数据模板（带*字段均是必填,请严格按照模板标准填入数据）", "台区台账数据信息");
        List<PullDown> pullDowns=new ArrayList<>();
        //电压等级
        List<DictData> devVoltage = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.DEV_VOLTAGE.getCode()).getData();
        //地区特征
        List<DictData> deviceRegionLype = dicDataFeignClient.getDicDataByTypeCode("Area").getData();
        //使用性质
        List<DictData> deviceUseNature = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.DEVICE_USERNATURE.getCode()).getData();
        //运行状态
        List<DictData> lineState = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.LINE_STATE.getCode()).getData();

        PullDown pullDown;
        pullDown=new PullDown();
        pullDown.setFirstCol(10);
        pullDown.setLastCol(10);
        pullDown.setStrings(devVoltage.stream().map(DictData::getName).collect(Collectors.toList()));
        pullDowns.add(pullDown);

        pullDown=new PullDown();
        pullDown.setFirstCol(12);
        pullDown.setLastCol(12);
        pullDown.setStrings(deviceRegionLype.stream().map(DictData::getName).collect(Collectors.toList()));
        pullDowns.add(pullDown);
        pullDown=new PullDown();
        pullDown.setFirstCol(13);
        pullDown.setLastCol(13);
        pullDown.setStrings(Arrays.asList("是","否"));
        pullDowns.add(pullDown);

        pullDown=new PullDown();
        pullDown.setFirstCol(14);
        pullDown.setLastCol(14);
        pullDown.setStrings(deviceUseNature.stream().map(DictData::getName).collect(Collectors.toList()));
        pullDowns.add(pullDown);

        pullDown=new PullDown();
        pullDown.setFirstCol(17);
        pullDown.setLastCol(17);
        pullDown.setStrings(lineState.stream().map(DictData::getName).collect(Collectors.toList()));
        pullDowns.add(pullDown);

        pullDown=new PullDown();
        pullDown.setFirstCol(20);
        pullDown.setLastCol(20);
        pullDown.setStrings(Arrays.asList("是","否"));
        pullDowns.add(pullDown);
        pullDown=new PullDown();
        pullDown.setFirstCol(22);
        pullDown.setLastCol(22);
        pullDown.setStrings(Arrays.asList("是","否"));
        pullDowns.add(pullDown);
        ExcelUtil.exportExcelPullDown(exportParams,"台区台账数据信息.xlsx",pullDowns, PowerDistributionAreaExcel.class, new ArrayList<>());
    }

    @Override
    public void importDistributionAreaExcel(List<PowerDistributionAreaExcel.ErrMsg> list, HttpServletResponse response){
        List<PowerDistributionarea> info=new ArrayList<>();
        List<PowerDistributionAreaExcel.ErrMsg> errInfo=new ArrayList<>();
        if(CollUtil.isNotEmpty(list)){
            PowerDistributionarea area;
            //获取部门信息
            List<PvTerminalTreeVO> depts = deptFeignClient.allDeptList().getData();
            //电压等级
            List<DictData> devVoltage = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.DEV_VOLTAGE.getCode()).getData();
            //地区特征
            List<DictData> deviceRegionLype = dicDataFeignClient.getDicDataByTypeCode("Area").getData();
            //使用性质
            List<DictData> deviceUseNature = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.DEVICE_USERNATURE.getCode()).getData();
            //运行状态
            List<DictData> lineState = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.LINE_STATE.getCode()).getData();
            for (PowerDistributionAreaExcel.ErrMsg msg : list) {
                String objNull = PubUtil.isObjNull(msg);
                if(StrUtil.isNotBlank(objNull)){
                    msg.setErrMsg(objNull);
                    errInfo.add(msg);
                    continue;
                }
                area=new PowerDistributionarea();
                area.setId(msg.getId());
                area.setName(msg.getName());
                List<PvTerminalTreeVO> deptList = depts.stream().filter(x -> x.getCode().contains(msg.getOrgId())).collect(Collectors.toList());
                if(CollUtil.isEmpty(deptList)){
                    String org = PubUtil.subString(msg.getOrgName().replace("国网",""));
                    List<PvTerminalTreeVO> deptName = depts.stream().filter(x -> x.getName().contains(org)).collect(Collectors.toList());
                    if(CollUtil.isNotEmpty(deptName)){
                        area.setOrgName(deptName.get(0).getName());
                        area.setOrgId(deptName.get(0).getCode());
                    }else{
                        msg.setErrMsg("组织机构不存在");
                        errInfo.add(msg);
                        continue;
                    }
                }else{
                    area.setOrgName(deptList.get(0).getName());
                    area.setOrgId(deptList.get(0).getCode());
                }
                area.setOperationName(msg.getOperationName());
                area.setOperationId(msg.getOperationId());
                area.setPowerrName(msg.getPowerrName());
                area.setPowerStationId(msg.getPowerStationId());
                area.setLineName(msg.getLineName());
                area.setLineId(msg.getLineId());
                area.setVoltageLevel(PubUtil.getDicById(msg.getVoltageLevel(),devVoltage));
                area.setPCapacity(msg.getPCapacity());
                area.setRegionalism(PubUtil.getDicById(msg.getRegionalism(),deviceRegionLype));
                area.setIfRuralPowerGrid("是".equals(msg.getIfRuralPowerGrid())?1:0);
                area.setNatureOfUse(PubUtil.getDicById(msg.getNatureOfUse(),deviceUseNature));
                area.setPowerSupplyRadius(msg.getPowerSupplyRadius());
                area.setLineLength(msg.getLineLength());
                area.setState(PubUtil.getDicById(msg.getState(),lineState));
                area.setDistributedPhotovoltaicNum(msg.getDistributedPhotovoltaicNum());
                area.setPhotovoltaicCapacity(msg.getPhotovoltaicCapacity());
                area.setIfBevAp("是".equals(msg.getIfBevAp())?1:0);
                area.setApLoadType(msg.getApLoadType());
                area.setIsUpToGrid("是".equals(msg.getIfBevAp())?1:0);
                area.setStatus(1);
                area.setInputStatus(0);
                area.setCreateBy(RequestUtil.getUserIndex());
                area.setCreateTime(LocalDateTimeUtil.now());
                area.setUpdateBy(RequestUtil.getUserIndex());
                area.setUpdateTime(LocalDateTimeUtil.now());
                info.add(area);
            }
            if(CollUtil.isNotEmpty(info)){
                info = info.stream().collect(Collectors.collectingAndThen
                        (Collectors.toCollection(() ->
                                new TreeSet<>(Comparator.comparing(o -> o.getId()))), ArrayList::new));
                List<String> ids = info.stream().map(PowerDistributionarea::getId).collect(Collectors.toList());
                List<PowerDistributionAreaExcel.ErrMsg> subInfo = list.stream().filter(x -> ids.contains(x.getId())).collect(Collectors.toList());
                addSub(subInfo,devVoltage);
                this.remove(new LambdaQueryWrapper<PowerDistributionarea>()
                        .in(PowerDistributionarea::getId, ids)
                );
                this.saveBatch(info, 1000);
            }
            if (CollUtil.isNotEmpty(errInfo)) {
                PubUtil.exportExcel(DateUtil.now() + "_台区台账错误信息.xlsx", errInfo,PowerDistributionAreaExcel.ErrMsg.class, response);
            }
        }
    }
    //变电站和线路插入
    public void addSub(List<PowerDistributionAreaExcel.ErrMsg> info,List<DictData> devVoltage) {
        List<StatationStat> stats=new ArrayList<>();
        StatationStat stat;
        List<GeneratrixWire> wires=new ArrayList<>();
        GeneratrixWire wire;
        List<StatationStat> oldStat = statationStatService.list();
        List<String> statIds = oldStat.stream().map(StatationStat::getPowerId).distinct().collect(Collectors.toList());
        List<GeneratrixWire> oldWire = generatrixWireService.list();
        List<String> wireIds = oldWire.stream().map(x-> x.getId()+"_"+x.getStationId()).distinct().collect(Collectors.toList());
        //变电站集合
        ArrayList<PowerDistributionAreaExcel.ErrMsg> statList = info.stream().collect(Collectors.collectingAndThen
                (Collectors.toCollection(() ->
                        new TreeSet<>(Comparator.comparing(o -> o.getPowerStationId()))), ArrayList::new));
        for (PowerDistributionAreaExcel.ErrMsg errMsg : statList) {
            if(!statIds.contains(errMsg.getPowerStationId())){
                stat=new StatationStat();
                stat.setPowerId(errMsg.getPowerStationId());
                stat.setPowerName(errMsg.getPowerrName());
                stat.setOrgId(errMsg.getOrgId());
                stat.setOrgName(errMsg.getOrgName());
                stat.setShouldBeNum(100);
                stat.setVoltageLevel(PubUtil.getDicById(errMsg.getVoltageLevel(),devVoltage));
                stat.setStatus(1);
                stat.setCreateBy(RequestUtil.getUserIndex());
                stat.setCreateTime(LocalDateTimeUtil.now());
                stat.setUpdateBy(RequestUtil.getUserIndex());
                stat.setUpdateTime(LocalDateTimeUtil.now());
                stats.add(stat);
            }
        }
        //线路
        ArrayList<PowerDistributionAreaExcel.ErrMsg> wireList = info.stream().collect(Collectors.collectingAndThen
                (Collectors.toCollection(() ->
                        new TreeSet<>(Comparator.comparing(o -> o.getLineId()+";"+o.getPowerStationId()))), ArrayList::new));
        for (PowerDistributionAreaExcel.ErrMsg errMsg : wireList){
            if(!wireIds.contains(errMsg.getLineId()+"_"+errMsg.getPowerStationId())){
                wire=new GeneratrixWire();
                wire.setId(errMsg.getLineId());
                wire.setName(errMsg.getLineName());
                wire.setStationId(errMsg.getPowerStationId());
                wire.setStationName(errMsg.getPowerrName());
                wire.setGeneratrixName(errMsg.getPowerrName());
                wire.setScale(PubUtil.getDicById(errMsg.getVoltageLevel(),devVoltage));
                wire.setStatus(1);
                wire.setCreateBy(RequestUtil.getUserIndex());
                wire.setCreateTime(LocalDateTimeUtil.now());
                wire.setUpdateBy(RequestUtil.getUserIndex());
                wire.setUpdateTime(LocalDateTimeUtil.now());
                wires.add(wire);
            }
        }
        if(CollUtil.isNotEmpty(stats)){
            statationStatService.saveBatch(stats);
        }
        if(CollUtil.isNotEmpty(wires)){
            generatrixWireService.saveBatch(wires);
        }

    }

    /**
     * 名称重复校验
     */
    private void checkName(PowerDistributionareaParam newParam, boolean flag){
        LambdaQueryWrapper<PowerDistributionarea> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(PowerDistributionarea::getName,newParam.getName());
        //修改
        if(!flag){
            lambdaQueryWrapper.ne(PowerDistributionarea::getId,newParam.getId());
        }
        int result = this.count(lambdaQueryWrapper);
        //大于等于1个则表示重复
        if (result >= 1) {
            throw new BusinessException(PmsDeviceResponseEnum.MODEL_NAME_REPEAT);
        }

    }
}
