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

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Maps;
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.modules.nh.factory.ginlong.dto.inverterdetaillist.GetInverterDetailR;
import org.springblade.modules.nh.mapper.MonitorInverterStatMapper;
import org.springblade.modules.nh.pojo.dto.sync.InverterHourlyEnergyDTO;
import org.springblade.modules.nh.pojo.entity.MonitorInverterDailyStatEntity;
import org.springblade.modules.nh.pojo.entity.MonitorInverterStatEntity;
import org.springblade.modules.nh.pojo.vo.MonitorInverterDailyStatVO;
import org.springblade.modules.nh.mapper.MonitorInverterDailyStatMapper;
import org.springblade.modules.nh.service.IMonitorInverterDailyStatService;
import org.springblade.modules.nh.service.IPowerStationService;
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 org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 逆变器日数据 服务实现类
 *
 * @author AlexWang
 * @since 2024-06-07
 */
@Service
@AllArgsConstructor
public class MonitorInverterDailyStatServiceImpl extends ServiceImpl<MonitorInverterDailyStatMapper, MonitorInverterDailyStatEntity> implements IMonitorInverterDailyStatService {

	private final MonitorInverterStatMapper monitorInverterStatMapper;

	@Override
	public Map<String, Object> getInverterGraph(String sn, String time) {
		time = time.substring(0,10);
		Map<String, Object> ret = new HashMap<>();
		List<Double> pacList = CommonUtil.repeatNum(24, 0d);
		List<Double> etdList = CommonUtil.repeatNum(24, 0d);
		ret.put("pac", pacList);
		ret.put("pacTimeList", CommonUtil.hourListFrom0());
		ret.put("etdTimeList", CommonUtil.hourListFrom1());
		ret.put("etd", etdList);

		MonitorInverterDailyStatEntity entity = findBySnAndDate(sn, time);

		if (entity != null) {
			for (int i = 0; i < 24; i++) {
				pacList.set(i, CommonUtil.getDoubleByFile(MonitorInverterDailyStatEntity.class,entity,String.format("jlgl%02d", i)));
				etdList.set(i, CommonUtil.getDoubleByFile(MonitorInverterDailyStatEntity.class,entity, String.format("h%02d", i + 1)));
			}
		}
		int hours = new Date().getHours();
		for (int i = 1; i < hours + 1; i++) {
			if (etdList.get(i) == 0) {
				etdList.set(i, etdList.get(i - 1));
			}
		}
		return ret;
	}

	@Override
	public MonitorInverterDailyStatEntity findBySnAndDate(String sn, String date) {
		LambdaQueryWrapper<MonitorInverterDailyStatEntity> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(MonitorInverterDailyStatEntity::getSn,sn)
			.eq(MonitorInverterDailyStatEntity::getStatDate,date);
		return this.getOne(queryWrapper);
	}


	@Override
	public IPage<MonitorInverterDailyStatVO> selectMonitorInverterDailyStatPage(IPage<MonitorInverterDailyStatVO> page, MonitorInverterDailyStatVO monitorInverterDailyStat) {
		return page.setRecords(baseMapper.selectMonitorInverterDailyStatPage(page, monitorInverterDailyStat));
	}


	@Override
	public List<MonitorInverterDailyStatEntity> findByInverterSnsAndDate(List<String> sns, String date, String sysType) {
//		SqlBuilder sb = new SqlBuilder()
//			.line("select * from crm_monitor_inverter_daily_stat")
//			.inst("where sn in", sns)
//			.line("and sys_type=?", sysType)
//			.line("and stat_date=?", date);
		LambdaQueryWrapper<MonitorInverterDailyStatEntity> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(MonitorInverterDailyStatEntity::getSysType,sysType)
			.eq(MonitorInverterDailyStatEntity::getStatDate,date)
			.in(MonitorInverterDailyStatEntity::getSn,sns);
		return this.list(queryWrapper);
	}

	@Override
	public void syncGinlongInverterForNowHour(List<GetInverterDetailR> list) {
		if (CollectionUtils.isEmpty(list)) {
			return;
		}
		Date now = new Date();
		List<InverterHourlyEnergyDTO> inverterHourlyEnergyDTOS = new ArrayList<>();
		for (GetInverterDetailR d : list) {
			Long dataTimestamp = d.getDataTimestamp();
			Date syncDate = new Date(dataTimestamp);
			Double todayEnergy = UnitUtil.convEnergy(d.getEToday(), d.getETodayStr());
			if (!DateUtil.isSameDay(now, syncDate)) {
				continue;
			}
			InverterHourlyEnergyDTO dto = new InverterHourlyEnergyDTO();
			dto.setSyncTime(syncDate);
			dto.setJlgl(UnitUtil.convPower(d.getPac(), d.getPacStr()));
			dto.setEnergy(todayEnergy);
			dto.setSn(d.getSn());
			inverterHourlyEnergyDTOS.add(dto);
		}
		syncHourlyData(NhConstants.SYS_TYPE_GINLONG, inverterHourlyEnergyDTOS);
	}

	@Override
	public void syncHourlyData(String sysType, List<InverterHourlyEnergyDTO> energyList) {
		if (energyList.isEmpty()) {
			return;
		}

		DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		Map<String, List<InverterHourlyEnergyDTO>> snGroups = energyList.stream().collect(Collectors.groupingBy(e -> {
			return inverterDailyKey(e.getSn(), df.format(e.getSyncTime()));
		}));
		sortSnDailyGroups(snGroups);
		Set<Map.Entry<String, List<InverterHourlyEnergyDTO>>> entries = snGroups.entrySet();
		List<MonitorInverterDailyStatEntity> inverterHourlyDataRecords = Lists.newArrayList();
		Set<String> sns = energyList.stream().map(InverterHourlyEnergyDTO::getSn).collect(Collectors.toSet());
		List<MonitorInverterStatEntity> inverterList = monitorInverterStatMapper.getInverterBySns(new ArrayList<>(sns), sysType);

		Map<String, MonitorInverterStatEntity> sn2InverterMap = inverterList.stream().collect(Collectors.toMap(MonitorInverterStatEntity::getSn, e -> e));
		Map<String, MonitorInverterDailyStatEntity> existsInverterDailyMap = getExistsInverterDaily(sysType, energyList, df);

		for (Map.Entry<String, List<InverterHourlyEnergyDTO>> entry : entries) {
			String key = entry.getKey();
			String[] split = key.split(";");
			String sn = split[0];
			String syncDate = split[1];
			MonitorInverterStatEntity inverterStat = sn2InverterMap.get(sn);
			if (inverterStat != null) {
				MonitorInverterDailyStatEntity hourlyData = createHourlyDataRecord(sn, syncDate, inverterStat.getOutInverterId(), existsInverterDailyMap, sysType, entry.getValue());
				if(hourlyData!=null && hourlyData.getId()==null){
					fillDefaultValue(hourlyData);
				}
				inverterHourlyDataRecords.add(hourlyData);
			}
		}
		this.saveOrUpdateBatch(inverterHourlyDataRecords);
	}

	private MonitorInverterDailyStatEntity createHourlyDataRecord(String sn,
															String date,
															String inverterId,
															Map<String, MonitorInverterDailyStatEntity> existsInverterDailyMap,
															String sysType,
															List<InverterHourlyEnergyDTO> hourlyEnergyDTOS) {
		MonitorInverterDailyStatEntity exists = existsInverterDailyMap.get(inverterDailyKey(sn, date));
		MonitorInverterDailyStatEntity r = exists;
		Date now = new Date();
		if (r == null) {
			r = new MonitorInverterDailyStatEntity();
			r.setCreateTime(now);
			r.setUpdateTime(now);
			r.setSysType(sysType);
			r.setStatDate(DateUtil.parseDate(date));
			r.setSn(sn);
			r.setOutInverterId(inverterId);
		}else{
			if(NhConstants.SYS_TYPE_GOODWE.equals(sysType)){
				boolean isEnergy = false;
				for (InverterHourlyEnergyDTO datum : hourlyEnergyDTOS){
					if(datum!=null && datum.getEnergy() !=null && datum.getEnergy()>0){
						isEnergy = true;
						break;
					}
				}
				if(isEnergy){
					for(int i=0;i<24;i++){
						String nl = String.format("h%02d", i + 1);
						CommonUtil.reflectSetField(r,nl,0d);
					}
				}

			}
		}

		for (InverterHourlyEnergyDTO datum : hourlyEnergyDTOS) {
			Date syncDate = datum.getSyncTime();
			int hours = syncDate.getHours(); // 0-23
			if (datum.getEnergy() != null) {
				String field = String.format("h%02d", hours + 1);
				Double val = (Double) CommonUtil.reflectGetField(r,field);
				if(val==null ){
					val = datum.getEnergy();
				}else{
					val = val + datum.getEnergy();
				}
				CommonUtil.reflectSetField(r,field,val);
			}
			if (datum.getJlgl() != null) {
				String field = String.format("jlgl%02d", hours);
				Double val = (Double) CommonUtil.reflectGetField(r,field);
				if(val==null ){
					val = datum.getJlgl();
				}else{
					val = val + datum.getJlgl();
				}
				CommonUtil.reflectSetField(r,field,val);
			}
			r.setSyncTime(syncDate);
		}
		return r;
	}

	private static void fillDefaultValue(MonitorInverterDailyStatEntity record){
		try{
		for (int i = 0; i < 24; i++) {
			String hCol = String.format("h%02d", i + 1);
			// 获取类的Class对象
			Class<?> cls = record.getClass();
			// 获取私有字段的Field对象
			Field hfield = cls.getDeclaredField(hCol);
			ReflectionUtils.makeAccessible(hfield);
			Object hval = ReflectionUtils.getField(hfield,record);
			if (hval == null) {
				ReflectionUtils.setField(hfield,record,0d);
			}
			String jlglCol = String.format("jlgl%02d", i);
			Field jfield = cls.getDeclaredField(jlglCol);
			ReflectionUtils.makeAccessible(jfield);
			Object jval = ReflectionUtils.getField(jfield,record);
			if (jval == null) {
				ReflectionUtils.setField(jfield,record,0d);
			}

		}}catch (Exception e){
			e.printStackTrace();
		}
	}

	private static void fillDefaultValue(List<MonitorInverterDailyStatEntity> createList) {
			for (MonitorInverterDailyStatEntity record : createList) {
				fillDefaultValue(record);
			}


	}

	private static String inverterDailyKey(String sn, String date) {
		return sn + ";" + date;
	}

	private void sortSnDailyGroups(Map<String, List<InverterHourlyEnergyDTO>> snGroups) {
		Set<Map.Entry<String, List<InverterHourlyEnergyDTO>>> entries = snGroups.entrySet();
		for (Map.Entry<String, List<InverterHourlyEnergyDTO>> entry : entries) {
			entry.getValue().sort(new Comparator<InverterHourlyEnergyDTO>() {
				@Override
				public int compare(InverterHourlyEnergyDTO o1, InverterHourlyEnergyDTO o2) {
					return (int) (o1.getSyncTime().getTime() - o2.getSyncTime().getTime());
				}
			});
		}
	}

	private Map<String, MonitorInverterDailyStatEntity> getExistsInverterDaily(String sysType, List<InverterHourlyEnergyDTO> energyList, DateFormat df) {
		Map<String, List<InverterHourlyEnergyDTO>> sameDateSnGroups = energyList.stream().collect(Collectors.groupingBy(e -> df.format(e.getSyncTime())));
		Map<String, MonitorInverterDailyStatEntity> snsDate2RecordMap = Maps.newHashMap();
		for (Map.Entry<String, List<InverterHourlyEnergyDTO>> stringListEntry : sameDateSnGroups.entrySet()) {
			String syncDate = stringListEntry.getKey();
			Set<String> sns = stringListEntry.getValue().stream().map(InverterHourlyEnergyDTO::getSn).collect(Collectors.toSet());
			List<MonitorInverterDailyStatEntity> exists = findByInverterSnsAndDate(new ArrayList<>(sns), syncDate, sysType);
			for (MonitorInverterDailyStatEntity exist : exists) {
				snsDate2RecordMap.put(inverterDailyKey(exist.getSn(), syncDate), exist);
			}
		}
		return snsDate2RecordMap;
	}
}
