package org.springblade.modules.nh.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.AllArgsConstructor;
import org.apache.commons.compress.utils.Lists;
import org.springblade.common.constant.NhConstants;
import org.springblade.common.utils.CommonUtil;
import org.springblade.common.utils.UnitUtil;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.nh.factory.ginlong.GinlongApi;
import org.springblade.modules.nh.factory.ginlong.IRet;
import org.springblade.modules.nh.factory.ginlong.dto.userstationlist.GetStationR;
import org.springblade.modules.nh.mapper.PowerStationMapper;
import org.springblade.modules.nh.pojo.dto.MonitorEntryStatDTO;
import org.springblade.modules.nh.pojo.dto.sync.StationIdMap;
import org.springblade.modules.nh.pojo.entity.MonitorEntryStatEntity;
import org.springblade.modules.nh.pojo.entity.MonitorEntryYearStatEntity;
import org.springblade.modules.nh.pojo.vo.MonitorEntryStatVO;
import org.springblade.modules.nh.excel.MonitorEntryStatExcel;
import org.springblade.modules.nh.mapper.MonitorEntryStatMapper;
import org.springblade.modules.nh.pojo.vo.PowerStationVO;
import org.springblade.modules.nh.service.IMonitorEntryStatService;
import org.springblade.modules.nh.service.IMonitorEntryYearStatService;
import org.springblade.modules.nh.wrapper.MonitorEntryStatWrapper;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 外部电站同步 服务实现类
 *
 * @author AlexWang
 * @since 2024-06-01
 */
@Service
@AllArgsConstructor
public class MonitorEntryStatServiceImpl extends ServiceImpl<MonitorEntryStatMapper, MonitorEntryStatEntity> implements IMonitorEntryStatService {

	private final GinlongApi ginlongApi;

	private final IMonitorEntryYearStatService yearStatService;

	private final PowerStationMapper powerStationMapper;

	private final BladeRedis bladeRedis;

	@Override
	public void updateGoodweEntryMonthYearData() {
		Long start = System.currentTimeMillis();

		LocalDate today = LocalDate.now();
		int currentYear = today.getYear();
		int currentMonth = today.getMonthValue();
		LambdaQueryWrapper<MonitorEntryStatEntity> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(MonitorEntryStatEntity::getType,NhConstants.SYS_TYPE_GOODWE);
		List<MonitorEntryStatEntity> list = this.list(queryWrapper);
		for (MonitorEntryStatEntity entryStat : list) {
			updateEntryYearData(entryStat, currentYear, currentMonth);
		}

		System.out.println("updateGoodweEntryMonthYearData:"+(System.currentTimeMillis()-start));
	}

	@Override
	public void updateEntryYearData(MonitorEntryStatEntity entryStat, int currentYear, int currentMonth) {
		Double monthEnergy = 0d;
		Double yearEnergy = 0d;
		LambdaQueryWrapper<MonitorEntryYearStatEntity> queryYearStat = new LambdaQueryWrapper<>();
		queryYearStat.eq(MonitorEntryYearStatEntity::getSysType, entryStat.getType())
			.eq(MonitorEntryYearStatEntity::getYear, currentYear)
			.eq(MonitorEntryYearStatEntity::getOutStationId, entryStat.getOutStationId());
		List<MonitorEntryYearStatEntity> yearStatEntityList = yearStatService.list(queryYearStat);
		for(MonitorEntryYearStatEntity yearStatEntity : yearStatEntityList){
			yearEnergy+=yearStatEntity.getEnergy();
			if(currentMonth ==yearStatEntity.getMonth()){
				if(yearStatEntity.getEnergy()>0){
					monthEnergy = yearStatEntity.getEnergy();
				}
			}
		}
		if(monthEnergy>0 || yearEnergy>0){
			LambdaUpdateWrapper<MonitorEntryStatEntity> updateWrapper = new LambdaUpdateWrapper<>();
			updateWrapper.eq(MonitorEntryStatEntity::getOutStationId, entryStat.getOutStationId())
				.set(MonitorEntryStatEntity::getEtm,monthEnergy)
				.set(MonitorEntryStatEntity::getEty,yearEnergy);
			if(entryStat.getEta()!=null && yearEnergy > entryStat.getEta()){
				updateWrapper.set(MonitorEntryStatEntity::getEta,yearEnergy);
			}
			this.update(updateWrapper);
		}
	}

	@Override
	public IPage<MonitorEntryStatVO> selectMonitorEntryStatPage(IPage<MonitorEntryStatVO> page, MonitorEntryStatVO monitorEntryStat) {
		return page.setRecords(baseMapper.selectMonitorEntryStatPage(page, monitorEntryStat));
	}


	@Override
	public List<MonitorEntryStatExcel> exportMonitorEntryStat(Wrapper<MonitorEntryStatEntity> queryWrapper) {
		List<MonitorEntryStatExcel> monitorEntryStatList = baseMapper.exportMonitorEntryStat(queryWrapper);
		//monitorEntryStatList.forEach(monitorEntryStat -> {
		//	monitorEntryStat.setTypeName(DictCache.getValue(DictEnum.YES_NO, MonitorEntryStat.getType()));
		//});
		return monitorEntryStatList;
	}

	@Override
	public MonitorEntryStatVO realTimeDetail(PowerStationVO vo) {
		if(vo==null || StringUtil.isBlank(vo.getOutStationId())){
			return null;
		}
		MonitorEntryStatEntity entryStat =  getMonitorEntryStatEntity(vo);
		if(entryStat== null){
			return null;
		}
		if(NhConstants.SYS_TYPE_GINLONG.equals(entryStat.getType())){
			IRet<GetStationR> ret =  ginlongApi.stationDetail(entryStat.getVendorIndex(),vo.getOutStationId());
			GetStationR r = ret.getData();
			if(r!=null){
				genEntryFromRemoteStation(entryStat,r);
			}
			this.updateById(entryStat);
		}
		return MonitorEntryStatWrapper.build().entityVO(entryStat);
	}

	@Override
	public MonitorEntryStatVO getByPowerStation(PowerStationVO vo) {
		if(vo==null || StringUtil.isBlank(vo.getOutStationId())){
			return null;
		}
		MonitorEntryStatEntity entryStat = getMonitorEntryStatEntity(vo);
		return MonitorEntryStatWrapper.build().entityVO(entryStat);
	}

	@Override
	public MonitorEntryStatEntity getByOutId(String outId) {
		PowerStationVO vo = new PowerStationVO();
		vo.setOutStationId(outId);
		return getMonitorEntryStatEntity(vo);
	}

	private MonitorEntryStatEntity getMonitorEntryStatEntity(PowerStationVO vo) {
		String outStationId = vo.getOutStationId();
		if(!StringUtil.isNotBlank(outStationId)){
			return null;
		}
		List<String> stationIds = Lists.newArrayList();
		for(String str:vo.getOutStationId().split(",")){
			stationIds.add(str);
		}

		LambdaQueryWrapper<MonitorEntryStatEntity>  queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.in(MonitorEntryStatEntity::getOutStationId,stationIds);
		List<MonitorEntryStatEntity> entryStatList = this.list(queryWrapper);
		MonitorEntryStatEntity entryStat = new MonitorEntryStatEntity();
		for(MonitorEntryStatEntity entryStatEntity : entryStatList){
			if(entryStat.getId()==null){
				BeanUtil.copyProperties(entryStatEntity,entryStat);
			}else{
				entryStat.setEtd(CommonUtil.sum(entryStat.getEtd(),entryStatEntity.getEtd()));
				entryStat.setEtm(CommonUtil.sum(entryStat.getEtm(),entryStatEntity.getEtm()));
				entryStat.setEty(CommonUtil.sum(entryStat.getEty(),entryStatEntity.getEty()));
				entryStat.setEta(CommonUtil.sum(entryStat.getEta(),entryStatEntity.getEta()));
			}
		}
		return entryStat;
	}

	@Override
	public List<String> getStationIds(String sysType) {
		return this.baseMapper.getStationIds(sysType);
	}
	@Override
	public List<String> getStationIds(String sysType,int index) {
		return this.baseMapper.getStationIdsByIndex(sysType,index);
	}

	@Override
	public MonitorEntryStatEntity findByStationId(String stationId) {
		LambdaQueryWrapper<MonitorEntryStatEntity> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(MonitorEntryStatEntity::getOutStationId,stationId);
		return this.getOne(queryWrapper);
	}

	@Override
	public void updateFisDate(String outStationId, String firstDate) {
		UpdateWrapper<MonitorEntryStatEntity> updateWrapper = new UpdateWrapper<>();
		updateWrapper.lambda()
			.eq(MonitorEntryStatEntity::getOutStationId,outStationId)
			.set(MonitorEntryStatEntity::getFisGenerateTime,firstDate);
		this.update(updateWrapper);
	}

	@Override
	public MonitorEntryStatDTO findByOutStationIds(List<String> stationIds) {
		return baseMapper.findByOutStationIds(stationIds);
	}

	@Override
	public void syncEntryStat(List<GetStationR> list, String sysType) {
		List<String> stationIds = list.stream().map(GetStationR::getId).collect(Collectors.toList());
		List<StationIdMap> stationIdsMaps = this.baseMapper.findByStationIds(stationIds);
		Map<String, Long> outStationId2LocalIdMap = stationIdsMaps.stream().collect(Collectors.toMap(StationIdMap::getOutStationId, StationIdMap::getId));

		List<GetStationR> updates = new ArrayList<>();
		for (GetStationR station : list) {
			String id = station.getId();
			if (outStationId2LocalIdMap.containsKey(id)) {
				updates.add(station);
			} else {
				MonitorEntryStatEntity stat = new MonitorEntryStatEntity();
				stat.setOutStationId(station.getId());
				stat.setType(sysType);
				stat.setVendorIndex(station.getVendorIndex());
				genEntryFromRemoteStation(stat, station);
				save(stat);
			}
		}

		if (!updates.isEmpty()) {
			if(NhConstants.SYS_TYPE_SAJ.equals(sysType)){
				return;
			}
			List<MonitorEntryStatEntity> rs = new ArrayList<>();
			List<String> normalIds = Lists.newArrayList();
			List<String> warnIds = Lists.newArrayList();
			List<String> offlineIds = Lists.newArrayList();


			for (GetStationR u : updates) {
				MonitorEntryStatEntity r = new MonitorEntryStatEntity();
				r.setVendorIndex(u.getVendorIndex());
				r.setId(outStationId2LocalIdMap.get(u.getId()));
				r.setOutStationId(u.getId());
				r.setType(sysType);
				r.setEtd(UnitUtil.convEnergy(u.getDayEnergy(), u.getDayEnergyStr()));
				r.setEtm(UnitUtil.convEnergy(u.getMonthEnergy(), u.getMonthEnergyStr()));
				r.setEty(UnitUtil.convEnergy(u.getYearEnergy(), u.getYearEnergyStr()));
				r.setEta(UnitUtil.convEnergy(u.getAllEnergy(), u.getAllEnergyStr()));

				r.setStationName(u.getStationName());

				r.setCapacity(UnitUtil.convPower(u.getCapacity(), u.getCapacityStr()));
				r.setState(u.getState());
				r.setFullHour(u.getFullHour());
				r.setSyncTime(new Date(u.getDataTimestamp()));
				r.setUpdateTime(new Date());
				r.setPower(UnitUtil.convPower(u.getPower(), u.getPowerStr()));

				if(u.getFisGenerateTime()!=null){
					r.setFisGenerateTime(new Date(u.getFisGenerateTime()));
				}
				rs.add(r);

				switch(u.getState()){
					case 1:normalIds.add(u.getId());break;
					case 2:offlineIds.add(u.getId());break;
					case 3:warnIds.add(u.getId());break;
				}
			}

			if(!normalIds.isEmpty()){
				powerStationMapper.updateStatusByOutIds(normalIds,1);
			}
			if(!warnIds.isEmpty()){
				powerStationMapper.updateStatusByOutIds(warnIds,2);
			}
			if(!offlineIds.isEmpty()){
				powerStationMapper.updateStatusByOutIds(offlineIds,3);
			}

			this.saveOrUpdateBatch(rs);
		}
	}

	private MonitorEntryStatEntity genEntryFromRemoteStation(MonitorEntryStatEntity stat, GetStationR station) {
		stat.setState(station.getState());
		stat.setEtd(UnitUtil.convEnergy(station.getDayEnergy(), station.getDayEnergyStr()));
		stat.setEtm(UnitUtil.convEnergy(station.getMonthEnergy(), station.getMonthEnergyStr()));
		stat.setEty(UnitUtil.convEnergy(station.getYearEnergy(), station.getYearEnergyStr()));
		stat.setEta(UnitUtil.convEnergy(station.getAllEnergy(), station.getAllEnergyStr()));
		stat.setStationName(station.getStationName());
		stat.setCapacity(UnitUtil.convPower(station.getCapacity(), station.getCapacityStr()));
		stat.setFullHour(station.getFullHour());
		stat.setCreateTime(new Date());
		stat.setSyncTime(new Date(station.getDataTimestamp()));
		if(station.getFisGenerateTime()!=null){
			stat.setFisGenerateTime(new Date(station.getFisGenerateTime()));
		}
		stat.setUpdateTime(new Date());
		stat.setPower(UnitUtil.convPower(station.getPower(), station.getPowerStr())); // 功率
		return stat;
	}

	@Override
	public MonitorEntryStatEntity getEntryStatInCache(String stationId) {
		if(StringUtil.isBlank(stationId)) return null;

		String STAT_TEMP_MAP_KEY = "stat_temp_map_key";
		String STAT_TEMP_MAP_TIME_KEY = "stat_temp_map_time_key";
		if(CommonUtil.isOutTime(bladeRedis.get(STAT_TEMP_MAP_TIME_KEY),15)){
			bladeRedis.del(STAT_TEMP_MAP_KEY);
			List<MonitorEntryStatEntity> statEntityList = this.list();
			for(MonitorEntryStatEntity statEntity : statEntityList){
				bladeRedis.hSet(STAT_TEMP_MAP_KEY,statEntity.getOutStationId(),statEntity);
			}
			bladeRedis.set(STAT_TEMP_MAP_TIME_KEY,System.currentTimeMillis());
		}

		return bladeRedis.hGet(STAT_TEMP_MAP_KEY,stationId);
	}

}
