/*
 * 文 件 名:  TaskService
 * 版    权:  华设设计集团股份有限公司
 * 描    述:  <描述>
 * 修 改 人:  lvwenbin
 * 修改时间:  2025/5/22
 * 跟踪单号:  <跟踪单号>
 * 修改单号:  <修改单号>
 * 修改内容:  <修改内容>
 */
package com.ruoyi.ems;

import com.ruoyi.ems.config.AnalysisConfig;
import com.ruoyi.ems.domain.Area;
import com.ruoyi.ems.domain.EmsFacs;
import com.ruoyi.ems.handle.BaCtlHandler;
import com.ruoyi.ems.model.QueryMeter;
import com.ruoyi.ems.service.IAreaService;
import com.ruoyi.ems.service.IEmsFacsService;
import com.ruoyi.ems.service.analysis.CarbonCalculationService;
import com.ruoyi.ems.service.analysis.ElecConsumeForecastService;
import com.ruoyi.ems.service.analysis.ElecProdForecastService;
import com.ruoyi.ems.service.analysis.EmsEcoAnalysisService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.List;

/**
 * 调度任务
 * <功能详细描述>
 *
 * @author lvwenbin
 * @version [版本号, 2025/5/22]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Configuration
public class TaskClacService {
    private static final Logger log = LoggerFactory.getLogger(TaskClacService.class);

    @Resource
    private IAreaService areaService;

    @Resource
    private IEmsFacsService facsService;


    @Resource
    private EmsEcoAnalysisService ecoAnalysisService;

    @Resource
    private ElecProdForecastService elecProdForecastService;

    @Resource
    private ElecConsumeForecastService elecConsumeForecastService;

    @Resource
    private CarbonCalculationService carbonCalculationService;

    @Resource
    private AnalysisConfig analysisConfig;

    @Qualifier("baCtlHandler")
    @Resource
    private BaCtlHandler baCtlHandler;

    /**
     * 节能分析
     */
    @Async
    @Scheduled(cron = "${analysis-task.eco-analysis.cron}")
    public void triggerEcoAnalysis() {
        log.debug("start eco analysis task.");
        DateTimeFormatter dateForm = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        try {
            // 获取今天的日期
            LocalDate today = LocalDate.now();
            LocalDate yesterday = today.minusDays(1);
            String date = yesterday.format(dateForm);

            String[] areaCodes = analysisConfig.getEcoAnalysisAreas();

            if (ArrayUtils.isNotEmpty(areaCodes)) {
                // 获取上个月的日期
                LocalDate lastMonth = today.minusMonths(1);

                // 获取上个月的第一天
                LocalDate firstDayOfLastMonth = lastMonth.withDayOfMonth(1);

                // 获取上个月的最后一天
                LocalDate lastDayOfLastMonth = lastMonth.with(TemporalAdjusters.lastDayOfMonth());

                for (String areaCode : areaCodes) {
                    QueryMeter queryMeter = new QueryMeter();
                    queryMeter.setAreaCode(areaCode);
                    queryMeter.setStartRecTime(firstDayOfLastMonth.format(dateForm));
                    queryMeter.setEndRecTime(lastDayOfLastMonth.format(dateForm));

                    ecoAnalysisService.executePvForecast(date, queryMeter);
                }
            }
        }
        catch (Exception e) {
            log.error("eco analysis fail!", e);
        }
    }

    /**
     * 光伏发电预测
     */
    @Async
    @Scheduled(cron = "${analysis-task.pv-forecast.cron}")
    public void pvForecastTask() {
        log.debug("start pv forecast task.");

        try {
            // 获取今天的日期
            LocalDate today = LocalDate.now();
            String[] areaCodes = analysisConfig.getPvForecastAreas();

            if (ArrayUtils.isNotEmpty(areaCodes)) {
                String adcode = analysisConfig.getAdcode();
                int prodForecastDays = analysisConfig.getProdForecastDays();

                for (String areaCode : areaCodes) {
                    EmsFacs param = new EmsFacs();
                    param.setRefArea(areaCode);
                    param.setFacsCategory("E");
                    List<EmsFacs> facsList = facsService.selectEmsFacsList(param);

                    if (CollectionUtils.isNotEmpty(facsList)) {
                        for (EmsFacs facs : facsList) {
                            elecProdForecastService.executePvForecast(adcode, areaCode, facs.getFacsCode(), today,
                                prodForecastDays);
                        }
                    }
                }
            }
        }
        catch (Exception e) {
            log.error("pv forecast fail!", e);
        }
    }

    /**
     * 用电预测
     */
    @Async
    @Scheduled(cron = "${analysis-task.elec-consume-forecast.cron}")
    public void elecConsumeForecastTask() {
        log.debug("start pv forecast task.");

        try {
            // 获取今天的日期
            LocalDate today = LocalDate.now();
            String[] areaCodes = analysisConfig.getElecConsumeAreas();

            if (ArrayUtils.isNotEmpty(areaCodes)) {
                for (String areaCode : areaCodes) {
                    //  区域用能预测
                    areaElecConsumeForecast(areaCode, today);

                    //  设施用能预测
                    facsElecConsumeForecast(areaCode, today);
                }
            }
        }
        catch (Exception e) {
            log.error("pv forecast fail!", e);
        }
    }

    /**
     * 碳计算（碳排碳汇）
     */
    @Async
    @Scheduled(cron = "${analysis-task.carbon-calculation.cron}")
    public void carbonCalculationTask() {
        log.debug("start carbon calculation task.");

        try {
            // 获取今天的日期
            LocalDate today = LocalDate.now();
            LocalDate yesterday = today.minusDays(1);
            String[] areaCodes = analysisConfig.getCarbonCalcAreas();

            if (ArrayUtils.isNotEmpty(areaCodes)) {
                for (String areaCode : areaCodes) {
                    // 碳排碳汇
                    carbonCalculationService.calculateDailyCarbonEmission(areaCode, yesterday);
                }
            }
        }
        catch (Exception e) {
            log.error("carbon calculation fail!", e);
        }
    }

    /**
     * 碳排预测
     */
    @Async
    @Scheduled(cron = "${analysis-task.carbon-forecast.cron}")
    public void carbonForecastTask() {
        log.debug("start carbon forecast task.");

        try {
            // 获取今天的日期
            LocalDate today = LocalDate.now();
            String[] areaCodes = analysisConfig.getCarbonForecastAreas();

            if (ArrayUtils.isNotEmpty(areaCodes)) {
                for (String areaCode : areaCodes) {
                    // 碳排碳汇
                    carbonCalculationService.calculateMonthCarbonForecast(areaCode, today);
                }
            }
        }
        catch (Exception e) {
            log.error("carbon calculation fail!", e);
        }
    }

    /**
     * 每小时产出设备计量数据
     */
    @Scheduled(cron = "0 0 0/1 * * ?")
    public void baMeterHourProd() {
        int cnt = baCtlHandler.meterHourProd();
        log.debug("产出室内能耗设备计量数据: {} 条", cnt);
    }

    private void areaElecConsumeForecast(String rootArea, LocalDate today) {
        List<Area> areas = areaService.selectAreaTree(rootArea, true);
        areaElecConsumeForecastSub(rootArea, areas, today);
    }

    private void areaElecConsumeForecastSub(String rootArea, List<?> areas, LocalDate today) {
        if (CollectionUtils.isNotEmpty(areas)) {
            for (Object obj : areas) {
                Area area = (Area) obj;
                elecConsumeForecastService.forecastAreas(analysisConfig.getAdcode(), rootArea, area, today,
                    analysisConfig.getElecConsumeForecastDays());

                if (CollectionUtils.isNotEmpty(area.getChildren())) {
                    List<?> children = area.getChildren();
                    areaElecConsumeForecastSub(rootArea, children, today);
                }
            }
        }
    }

    private void facsElecConsumeForecast(String areaCode, LocalDate today) {
        EmsFacs param = new EmsFacs();
        param.setRefArea(areaCode);
        param.setFacsCategory("Z");
        List<EmsFacs> facsList = facsService.selectEmsFacsList(param);

        if (CollectionUtils.isNotEmpty(facsList)) {
            for (EmsFacs facs : facsList) {
                elecConsumeForecastService.forecastFacilities(analysisConfig.getAdcode(), areaCode, facs, today,
                    analysisConfig.getElecConsumeForecastDays());
            }
        }
    }
}