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

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.huashe.common.domain.model.DateAttr;
import com.huashe.common.domain.model.WeatherForecast;
import com.huashe.common.domain.model.WeatherRt;
import com.huashe.common.exception.Assert;
import com.huashe.common.utils.HttpUtils;
import com.ruoyi.ems.config.DateAttrConfig;
import com.ruoyi.ems.config.WeatherConfig;
import com.ruoyi.ems.core.ObjectCache;
import com.ruoyi.ems.handle.AcrelElecMonitorHandler;
import com.ruoyi.ems.handle.BaCtlHandler;
import com.ruoyi.ems.handle.GeekOpenCbHandler;
import com.ruoyi.ems.handle.GrowattHandler;
import com.ruoyi.ems.handle.SquareLightCtlHandler;
import com.ruoyi.ems.service.IDateService;
import com.ruoyi.ems.service.IWeatherService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.URIBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.Year;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * 任务调度
 * <功能详细描述>
 *
 * @author lvwenbin
 * @version [版本号, 2025/3/18]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Service
public class TaskColExecutor {
    /**
     * 日志服务
     */
    protected static final Logger log = LoggerFactory.getLogger(TaskColExecutor.class);

    @Resource
    private WeatherConfig weatherConfig;

    @Resource
    private DateAttrConfig holidayConfig;

    @Resource
    private IWeatherService weatherService;

    @Resource
    private IDateService dateService;

    @Autowired
    private ObjectCache objectCache;

    @Qualifier("geekOpenCbHandler")
    @Resource
    private GeekOpenCbHandler geekOpenCbHandler;

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

    @Qualifier("squareLightCtlHandler")
    @Resource
    private SquareLightCtlHandler squareLightCtlHandler;

    @Qualifier("acrelElecMonitorHandler")
    @Resource
    private AcrelElecMonitorHandler acrelElecMonitorHandler;

    @Qualifier("growattHandler")
    @Resource
    private GrowattHandler growattHandler;

    /**
     * 定时清理过期设备上报响应
     */
    @Scheduled(cron = "0 0/10 * * * ?")
    public void cleanDevResCache() {
        int cnt = objectCache.cleanDevResCache();
        log.debug("清理过期设备上报响应: {} 条", cnt);
    }

    /**
     * 定时刷新设备在线状态
     */
    @Scheduled(cron = "0 0/5 * * * ?")
    public void refresh5min() {
        CompletableFuture.runAsync(() -> squareLightCtlHandler.execSyncDevAttrAll());
        CompletableFuture.runAsync(() -> squareLightCtlHandler.refreshOnline());
        CompletableFuture.runAsync(() -> acrelElecMonitorHandler.execSyncDevAttrAll());
        CompletableFuture.runAsync(() -> growattHandler.refreshOnline());
    }

//    /**
//     * 每小时产出设备计量数据
//     */
//    @Scheduled(cron = "0 0 0/1 * * ?")
//    public void geekOpenMeterHourProd() {
//        int cnt1 = geekOpenCbHandler.meterHourProd();
//        log.debug("产出GeekOpen设备计量数据: {} 条", cnt1);
//    }

    /**
     * 每15min采集能耗数据
     */
    @Scheduled(cron = "0 0/15 * * * ?")
    public void baMeterCollect() {
        CompletableFuture.runAsync(() -> {
            baCtlHandler.meterCollect();
            baCtlHandler.xfCollect();
            baCtlHandler.ahuCollect();
            baCtlHandler.wtCollect();
            baCtlHandler.wpCollect();
            baCtlHandler.lightCollect();
        });

        CompletableFuture.runAsync(() -> growattHandler.execCollectInverterData());
    }

    /**
     * 天气实况采集
     */
    @Async
    @Scheduled(cron = "${general-data.weather.rt.cron}")
    public void collectRt() {
        log.debug("start collect weather rt.");

        try {
            URIBuilder uriBuilder = new URIBuilder(weatherConfig.getWeatherRtAddr());
            uriBuilder.addParameter("adcode", weatherConfig.getAdcode())
                .addParameter("apiKey", weatherConfig.getApiKey());
            String res = HttpUtils.doGet(uriBuilder);
            log.debug("get res:\r\n{}", res);

            JSONObject jsonObject = JSON.parseObject(res);

            String code = jsonObject.getString("code");
            Assert.isTrue(StringUtils.equals(code, "0"), -1, jsonObject.getString("message"));

            String data = jsonObject.getString("data");

            if (data != null) {
                WeatherRt weatherRt = JSONObject.parseObject(data, WeatherRt.class);
                weatherService.mergeRt(weatherRt);
            }
        }
        catch (Exception e) {
            log.error("collectRt fail!", e);
        }
    }

    /**
     * 天气预报采集
     */
    @Async
    @Scheduled(cron = "${general-data.weather.forecast.cron}")
    public void collectForecast() {
        log.debug("start collect weather forecast.");

        try {
            URIBuilder uriBuilder = new URIBuilder(weatherConfig.getWeatherForecastAddr());
            uriBuilder.addParameter("adcode", weatherConfig.getAdcode())
                .addParameter("apiKey", weatherConfig.getApiKey());
            String res = HttpUtils.doGet(uriBuilder);
            log.debug("get res:\r\n{}", res);

            JSONObject jsonObject = JSON.parseObject(res);

            String code = jsonObject.getString("code");
            Assert.isTrue(StringUtils.equals(code, "0"), -1, jsonObject.getString("message"));

            JSONArray data = jsonObject.getJSONArray("data");
            Assert.notNull(data, -1, "weather list is null.");

            if (!data.isEmpty()) {
                List<WeatherForecast> forecastList = JSON.parseArray(data.toString(), WeatherForecast.class);

                if (CollectionUtils.isNotEmpty(forecastList)) {
                    weatherService.deleteForecastByAdcode(weatherConfig.getAdcode());
                    weatherService.insertForecastBacth(forecastList);
                }
            }
        }
        catch (Exception e) {
            log.error("collectForecast fail!", e);
        }
    }

    /**
     * 节假日采集
     */
    @Async
    @Scheduled(cron = "${general-data.date.cron}")
    public void collectDateAttr() {
        log.debug("start collect date attr.");

        try {
            // 获取当前年份
            int currentYear = Year.now().getValue();

            // 本年第一天
            LocalDate firstDay = LocalDate.of(currentYear, 1, 1);

            // 本年最后一天（12月31日）
            LocalDate lastDay = LocalDate.of(currentYear, 12, 31);

            // 定义日期格式
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

            URIBuilder uriBuilder = new URIBuilder(holidayConfig.getApiAddr());
            uriBuilder.addParameter("startDate", formatter.format(firstDay))
                .addParameter("endDate", formatter.format(lastDay)).addParameter("apiKey", weatherConfig.getApiKey());
            String res = HttpUtils.doGet(uriBuilder);
            log.debug("get res:\r\n{}", res);

            JSONObject jsonObject = JSON.parseObject(res);

            String code = jsonObject.getString("code");
            Assert.isTrue(StringUtils.equals(code, "0"), -1, jsonObject.getString("message"));

            JSONArray data = jsonObject.getJSONArray("data");
            Assert.notNull(data, -1, "date attr is null.");

            if (!data.isEmpty()) {
                List<DateAttr> dateAttrs = JSON.parseArray(data.toString(), DateAttr.class);

                if (CollectionUtils.isNotEmpty(dateAttrs)) {
                    dateService.deleteByYear(String.valueOf(currentYear));
                    dateService.insertBatch(dateAttrs);
                }
            }
        }
        catch (Exception e) {
            log.error("collect date attr fail!", e);
        }
    }
}