package org.springblade.modules.nh.job;


import cn.hutool.core.math.MathUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springblade.common.cache.DictCache;
import org.springblade.common.constant.NhConstants;
import org.springblade.common.enums.DictEnum;
import org.springblade.common.utils.CommonUtil;
import org.springblade.common.utils.TaskControl;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.tool.utils.*;
import org.springblade.modules.nh.pojo.entity.*;
import org.springblade.modules.nh.pojo.vo.MonitorEntryMonthStatVO;
import org.springblade.modules.nh.pojo.vo.MonitorEntryStatVO;
import org.springblade.modules.nh.service.*;
import org.springblade.modules.nh.wrapper.PowerStationWrapper;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.*;
import java.time.temporal.ChronoUnit;
import java.util.*;

@EnableScheduling
@Component
@Slf4j
@AllArgsConstructor
public class InefficientScheduler {

	private final IPowerStationService powerStationService;

	private final IMonitorEntryStatService entryStatService;

	private final IMonitorEntryMonthStatService entryMonthStatService;

	private final IMonitorInverterStatService inverterStatService;

	private final IMonitorInverterDailyStatService dailyStatService;

	private final IInefficientSettingService settingService;

	private final IPowerStationInefficientService inefficientService;

	private final BladeRedis bladeRedis;

	private final String avgKey = "CAL_AVG_PS_HOURS";

	// 每周一早上0点统计上周的低效电站
	@Scheduled(cron = "30 13 4 * * ?")
	public void calInefficientPowerStation() {
		if(!isTimeToCal()){
			return;
		}

		TaskControl.runTask("inefficient:calInefficientPowerStation", new Runnable() {
			@Override
			public void run() {
				List<InefficientSettingEntity> settingList = settingService.list();
				settingList.forEach(setting->{
					calInefficientSetting(setting);
				});
			}
		});
	}

	// 按资方-安装类型-地区 计算所有电站的平均发电时间
	@Scheduled(cron = "40 34 1 * * ?")
	public void calAvgPowerStationHours() {
		if(!isTimeToCal()){
			return;
		}
		TaskControl.runTask("inefficient:calInefficientPowerStation", new Runnable() {
			@Override
			public void run() {
				executeAvgHours();
			}
		});
	}

	public void executeAvgHours(){
		LambdaQueryWrapper<PowerStationEntity> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.isNotNull(PowerStationEntity::getOutStationId);
		List<PowerStationEntity> powerStationEntities = powerStationService.list(queryWrapper);

		Map<String,List<Double>> map = Maps.newHashMap();
		int i=0;
		for (PowerStationEntity ps : powerStationEntities) {
			Date start = getStartDate();
			Date end = getEndDate();
			Double weekHours = getStationLastWeekHours(ps,start,end);
			System.out.println(i++);
			if(weekHours>0){
				//计算有发电时间的-省
				String typeAvgKey = getTypeKey(ps);
				if(map.containsKey(typeAvgKey)){
					map.get(typeAvgKey).add(weekHours);
				}else{
					List<Double> typeList = Lists.newArrayList();
					typeList.add(weekHours);
					map.put(typeAvgKey, typeList);
				}
				//计算有发电时间的-市
				String typeAvgKeyCity = getTypeKeyCity(ps);
				if(map.containsKey(typeAvgKeyCity)){
					map.get(typeAvgKeyCity).add(weekHours);
				}else{
					List<Double> typeList = Lists.newArrayList();
					typeList.add(weekHours);
					map.put(typeAvgKeyCity, typeList);
				}
			}
		}

		bladeRedis.del(avgKey);
		for (Map.Entry<String, List<Double>> entry : map.entrySet()) {
			List<Double> hoursList= entry.getValue();
			Double sum = hoursList.stream().mapToDouble(Double::doubleValue).sum();
			Double avgHours = sum/hoursList.size();
			bladeRedis.hSet(avgKey,entry.getKey(),avgHours);
		}
	}

	public void calInefficientSetting(InefficientSettingEntity setting) {
		String planType = DictCache.getValue(DictEnum.SETTING_PLAN_TYPE,setting.getPlanType());

		List<String> citys = Lists.newArrayList();
		if(StringUtil.isNotBlank(setting.getCitys())){
			String[] tempCitys = null;
			if(setting.getCitys().contains(",")){
				tempCitys = setting.getCitys().split(",");
			}else{
				tempCitys = setting.getCitys().split("、");
			}
			for(String city : tempCitys){
				if(StringUtil.isNotBlank(city)){
					if(!city.contains("市")){
						citys.add(city+"市");
					}else{
						citys.add(city);
					}
				}
			}
		}
		LambdaQueryWrapper<PowerStationEntity> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper
			.eq(PowerStationEntity::getCapitalName,setting.getCapitalName())
			.eq(PowerStationEntity::getInstallType,planType)
//			.eq(PowerStationEntity::getCustomerType,setting.getCustomerType())
//			.eq(PowerStationEntity::getFilingType,setting.getRecordType())
			.eq(PowerStationEntity::getProvince,setting.getProvince())
			.eq(PowerStationEntity::getApplyStatus,1)
			.isNotNull(PowerStationEntity::getOutStationId);
		if(CollectionUtil.isNotEmpty(citys)){
			queryWrapper.in(PowerStationEntity::getCity,citys);
		}

		List<PowerStationEntity> powerStationEntities = powerStationService.list(queryWrapper);
		for (PowerStationEntity ps : powerStationEntities) {
			calIneffiectStation(setting, ps, CollectionUtil.isNotEmpty(citys)?2:1);
		}

	}

	public PowerStationInefficientEntity calIneffiectStation(InefficientSettingEntity setting, PowerStationEntity ps, int type) {
		Calendar calendar = Calendar.getInstance();
		int currentMonth = calendar.get(Calendar.MONTH) + 1;

		Double monthGuardHours = (Double) CommonUtil.reflectGetField(setting,"guardHourM"+currentMonth);
		Double weekGuardHours = monthGuardHours*getDaysBetween()/CommonUtil.getDaysInCurrentMonth();
		Date end = getEndDate();
		Date start = getStartDate();
		Double avgHours = getAvgHours(ps,type);
		Double weekHours = getStationLastWeekHours(ps,start,end);

		PowerStationInefficientEntity inefficientEntity = null;
		if(weekHours <= 0){
			return null;
		}

		int flag = 0;
		if(avgHours>0 && weekHours/avgHours < 0.9){
			flag++;
		}
		Double guardRate = CommonUtil.retainDoubleNum(weekHours/weekGuardHours,3);
		if(guardRate<0.9){
			flag++;
		}


		if(flag>0){
			inefficientEntity = BeanUtil.copyProperties(ps,PowerStationInefficientEntity.class);
			inefficientEntity.setStationId(ps.getId());
			inefficientEntity.setInstallType(ps.getInstallType());
			inefficientEntity.setCapacity(ps.getActualCapacity().doubleValue());
			inefficientEntity.setGuardHour(weekGuardHours);
			inefficientEntity.setMgHour(weekHours);
			inefficientEntity.setAvgHour(avgHours);
			inefficientEntity.setGuardRate(guardRate);
			inefficientEntity.setFinishRate(CommonUtil.retainDoubleNum(weekHours/ setting.getGuardHourTotal(),3));
			inefficientEntity.setInstallAddress(ps.getProvince()+ ps.getCity()+ ps.getDistrict()+ ps.getAddress());

			inefficientEntity.setStatus(NhConstants.INEFFICIENT_STATION_STATION_TODO);
			MonitorEntryStatVO entryStatVO = entryStatService.getByPowerStation(PowerStationWrapper.build().entityVO(ps));
			if (entryStatVO != null) {
				inefficientEntity.setOtm(entryStatVO.getEtm());
			}
			inefficientEntity.setId(null);
			inefficientEntity.setStart(start);
			inefficientEntity.setEnd(end);
			inefficientEntity.setIsConfirm(flag==1?"0":"1");

			LambdaQueryWrapper<PowerStationInefficientEntity> lqw = new LambdaQueryWrapper<>();
			lqw.eq(PowerStationInefficientEntity::getStationId, ps.getId())
				.eq(PowerStationInefficientEntity::getStatus,0);
			if(inefficientService.count(lqw)==0){
				inefficientService.save(inefficientEntity);
			}
		}
		return inefficientEntity;
	}

	private Double getStationLastWeekHours(PowerStationEntity ps,Date start,Date end){
		Double hours = 0.0D;
		if(StringUtil.isNotBlank(ps.getOutStationId())){
			try{
				String[] outStationIds = ps.getOutStationId().split(",");
				//获取电站所有逆变器的外部逆变器id
				Double totalEnergy = entryMonthStatService.sumEnergy(Arrays.asList(outStationIds),start,end);
				hours = totalEnergy/ps.getActualCapacity().doubleValue();
			}catch (Exception e){
				log.error("获取电站等效时间错误:{}",e);
			}

		}
		return hours;
	}

	private Double sumDaysHours(MonitorInverterDailyStatEntity dailyStat){
		Double dayHours = 0.0D;
		if(dailyStat==null) return dayHours;

		Double lastHourPower = 0D;
		for(int i=1;i<=24;i++){
			String fieldKet = i+"";
			if(i<10){
				fieldKet = "0"+fieldKet;
			}
			Object obj = CommonUtil.reflectGetField(dailyStat,"h"+fieldKet);
			if(obj!=null){
				Double val = (Double)obj;
				if(val>lastHourPower){
					dayHours += 1;
					lastHourPower = (Double) obj;
				}
				if(val == 0 && lastHourPower > 0){
					break;
				}
			}
		}
		return dayHours;
	}

	private static long getDaysBetween(){
		Date startDate = getStartDate();
		LocalDate end = LocalDate.now();

		// 将 java.util.Date 转换为 Instant
		Instant instant = startDate.toInstant();
		// 将 Instant 与时区（例如系统默认时区）结合，获取 ZonedDateTime
		ZoneId zoneId = ZoneId.systemDefault(); // 也可以指定其他时区，例如 ZoneId.of("UTC")
		ZonedDateTime zonedDateTime = instant.atZone(zoneId);
		// 从 ZonedDateTime 中提取 LocalDate
		LocalDate start = zonedDateTime.toLocalDate();
		long ret = ChronoUnit.DAYS.between(start, end);
		return ret;
	}

	private static Date getEndDate(){
		String todayStr = DateUtil.format(new Date(), "yyyy-MM-dd");
		return DateUtil.parse(todayStr,"yyyy-MM-dd");
	}

	private static Date getStartDate(){
		Date start = null;
		String todayStr = DateUtil.format(new Date(), "yyyy-MM-dd");
		if(dayOfMonth()==1){
			LocalDate today = LocalDate.now();
			int lastMonth = today.getMonthValue()-1;
			String month = String.format("%02d",lastMonth);
			String startStr = DateUtil.format(new Date(),"yyyy")+"-"+month+"-22";
			start = DateUtil.parse(startStr,"yyyy-MM-dd");
		}else{
			Date today = DateUtil.parse(todayStr,"yyyy-MM-dd");
			start = DateUtil.minusDays(today,7);
		}
		return start;
	}

	private static boolean isTimeToCal(){
		int[] days = new int[]{1,8,15,22};
		for(int day:days){
			if(dayOfMonth()==day) {
				return true;
			};
		}
		return false;
	}

	private static int dayOfMonth(){
		// 获取当前日期
		LocalDate today = LocalDate.now();
		// 获取当前月份的第一天
		LocalDate firstDayOfMonth = today.withDayOfMonth(1);
		// 计算今天是本月的第几天
		int dayOfMonth = (int) (today.toEpochDay() - firstDayOfMonth.toEpochDay()) + 1;
		return dayOfMonth;
	}

	private String getTypeKey(PowerStationEntity ps){
		String key =  ps.getCapitalName()+"_"+ps.getInstallType()+"_"+ps.getProvince();
		return Func.md5Hex(key);
	}
	private String getTypeKeyCity(PowerStationEntity ps){
		String key =  ps.getCapitalName()+"_"+ps.getInstallType()+"_"+ps.getProvince()+"_"+ps.getCity();
		return Func.md5Hex(key);
	}

	public Double getAvgHours(PowerStationEntity ps,int type){
		Double ret = 0D;
		if(type==1){
			//根据省获取发电量
			String typeAvgKey = getTypeKey(ps);
			ret = bladeRedis.hGet(avgKey,typeAvgKey);
		}
		if(type==2){
			//根据省获取发电量
			String typeAvgKey = getTypeKeyCity(ps);
			ret = bladeRedis.hGet(avgKey,typeAvgKey);
		}
		if(ret == null){
			ret = 0D;
		}
		return ret;
	}

	public Double getAvgHoursDefault(PowerStationEntity ps){
		//根据市获取发电量
		String typeAvgKey = getTypeKeyCity(ps);
		Double ret = bladeRedis.hGet(avgKey,typeAvgKey);
		if(ret == null || ret == 0){
			//根据省获取发电量
			typeAvgKey = getTypeKey(ps);
			ret = bladeRedis.hGet(avgKey,typeAvgKey);
		}
		if(ret == null){
			ret = 0D;
		}
		return ret;
	}

	private Double getAvgHoursCity(PowerStationEntity ps){
		String typeAvgKey = getTypeKeyCity(ps);
		Double ret = bladeRedis.hGet(avgKey,typeAvgKey);
		if(ret == null){
			ret = 0D;
		}
		return ret;
	}

	public static void main(String[] args) {
		System.out.println(getDaysBetween());
	}

}
