package com.xueyi.system.emcs.controller;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.xueyi.common.core.web.result.AjaxResult;
import com.xueyi.common.core.web.validate.V_A;
import com.xueyi.common.core.web.validate.V_E;
import com.xueyi.common.log.annotation.Log;
import com.xueyi.common.log.enums.BusinessType;
import com.xueyi.common.mqtt.connection.MqttTemplate;
import com.xueyi.common.security.annotation.RequiresPermissions;
import com.xueyi.common.web.entity.controller.BaseController;
import com.xueyi.system.api.digitalmans.domain.vo.NumberOfAlertToChartVo;
import com.xueyi.system.emcs.domain.dto.DmExceptionLogDto;
import com.xueyi.system.emcs.domain.dto.RedisBaseDto;
import com.xueyi.system.emcs.domain.query.DmExceptionLogQuery;
import com.xueyi.system.emcs.service.BaseRedisListDataCache;
import com.xueyi.system.emcs.service.IDmExceptionLogService;
import com.xueyi.system.emcs.service.LogMqttMessageHandler;
import com.xueyi.system.emcs.service.impl.DmExceptionLogServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.Serializable;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 数字人状态事件上报日志管理 业务处理
 *
 * @author xueyi
 */
@RestController
@RequestMapping("/log")
public class DmExceptionLogController extends BaseController<DmExceptionLogQuery, DmExceptionLogDto, IDmExceptionLogService> {
    private  final static String HEART_MQTT_PREFIX = "digital-man";

    private final static String[] CHART_TYPES = new String[]{"network", "cpu", "memory"};
    @Autowired
    private MqttTemplate mqttTemplate;

    @Autowired
    private  LogMqttMessageHandler logMqttMessageHandler;

    @Autowired
    private BaseRedisListDataCache baseRedisListDataCache;

    @Autowired
    private DmExceptionLogServiceImpl exceptionLogService;

    /** 定义节点名称 */
    @Override
    protected String getNodeName() {
        return "数字人状态事件上报日志" ;
    }


    /**
     * 查询数字人状态事件上报日志列表
     */
    @Override
    @GetMapping("/list")
    @RequiresPermissions(Auth.DM_EXCEPTION_LOG_LIST)
    public AjaxResult list(DmExceptionLogQuery exceptionLog) {
        return super.list(exceptionLog);
    }

    /**
     * 查询数字人状态事件上报日志详细
     */
    @Override
    @GetMapping(value = "/{id}")
    @RequiresPermissions(Auth.DM_EXCEPTION_LOG_SINGLE)
    public AjaxResult getInfo(@PathVariable Serializable id) {
        return super.getInfo(id);
    }

    /**
     * 数字人状态事件上报日志新增
     */
    @Override
    @PostMapping
    @RequiresPermissions(Auth.DM_EXCEPTION_LOG_ADD)
    @Log(title = "数字人状态事件上报日志管理", businessType = BusinessType.INSERT)
    public AjaxResult add(@Validated({V_A.class}) @RequestBody DmExceptionLogDto exceptionLog) {
        return super.add(exceptionLog);
    }

    /**
     * 数字人状态事件上报日志修改
     */
    @Override
    @PutMapping
    @RequiresPermissions(Auth.DM_EXCEPTION_LOG_EDIT)
    @Log(title = "数字人状态事件上报日志管理", businessType = BusinessType.UPDATE)
    public AjaxResult edit(@Validated({V_E.class}) @RequestBody DmExceptionLogDto exceptionLog) {
        if (exceptionLog == null || exceptionLog.getId() == null) {
            return error("参数不合法");
        }
        DmExceptionLogDto dto = exceptionLogService.selectById(exceptionLog.getId());
        dto.setAlertStatus(exceptionLog.getAlertStatus());
        dto.setEndTime(LocalDateTime.now());
        return super.edit(dto);
    }

    public static List<String> getRecentHourTimes() {
        List<String> recentHourTimes = new ArrayList<>();

        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();

        // 获取一个小时前的时间
        LocalDateTime oneHourAgo = now.minusHours(1);

        // 从一个小时前的时间开始，每分钟递增，直到当前时间
        LocalDateTime current = oneHourAgo;
        while (current.isBefore(now)) {
            // 格式化时间为HH:mm
            String formattedTime = current.format(DateTimeFormatter.ofPattern("HH:mm"));

            // 添加到列表中
            recentHourTimes.add(formattedTime);

            // 当前时间加一分钟
            current = current.plusMinutes(1);
        }

        return recentHourTimes;
    }

    @GetMapping( value = "/chart/{devId}")
    public AjaxResult queryChartData(@PathVariable String devId) {
        JSONObject json = new JSONObject();

        List<String> times = getRecentHourTimes();
        Arrays.stream(CHART_TYPES).toList().forEach(item->{
            List<Serializable> redisList = new ArrayList<>();
            String key = HEART_MQTT_PREFIX + ":" + devId + ":" + item;
            redisList = baseRedisListDataCache.getList(key);
            if (redisList!= null && redisList.size() > 0) {
                RedisBaseDto baseDto = (RedisBaseDto) redisList.get(redisList.size()-1);
                String occur = baseDto.getOccurTime();
                String last = times.get(times.size()-1);
                LocalTime localTime1 = LocalTime.parse(occur);
                LocalTime localTime2 = LocalTime.parse(last);
                LocalTime localTime = localTime2.minusMinutes(3);
                if (localTime.compareTo(localTime1) > 0 ){
                    JSONObject redisDto = new JSONObject();
                    redisDto.put("occurTime", localTime2.format(DateTimeFormatter.ofPattern("HH:mm")));
                    redisDto.put("val", "N");
                    redisList.add(redisDto);
                }
            } else {
                String last = times.get(times.size()-1);
                LocalTime localTime2 = LocalTime.parse(last);
                JSONObject redisDto = new JSONObject();
                redisDto.put("occurTime", localTime2.format(DateTimeFormatter.ofPattern("HH:mm")));
                redisDto.put("val", "N");
                redisList.add(redisDto);
            }
//            redisList.get(redisList.size()-1);
            json.put(item, redisList);
        });

        System.err.println(getRecentHourTimes());

        return success(json);
    }

    /**
     * 数字人状态事件上报日志批量删除
     */
    @Override
    @DeleteMapping("/batch/{idList}")
    @RequiresPermissions(Auth.DM_EXCEPTION_LOG_DEL)
    @Log(title = "数字人状态事件上报日志管理", businessType = BusinessType.DELETE)
    public AjaxResult batchRemove(@PathVariable List<Long> idList) {
        return super.batchRemove(idList);
    }

    @GetMapping("/range_alerts_to_chart")
    public AjaxResult rangeAlertsToChart() {
        JSONObject jsonObject = new JSONObject();
        List<NumberOfAlertToChartVo> rangeBy5Weeks = new ArrayList<>();
        // select nearly 5 weeks alerts from dm_exception_log
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime startL = LocalDateTime.now();
        LocalDateTime endL = null;
        for (int i = 0;i < 5;i++) {
            // 格式化日期时间
            // 把startL设置当前时间减一周后的周一00:00:00
            startL = startL.with(DayOfWeek.MONDAY).withHour(0).withMinute(0).withSecond(0);
            // 把endL设置成周日23:59:59，如果是当前一周，设置成当前时间
            if (i == 0) {
                endL = LocalDateTime.now();
            } else {
                endL = startL.with(DayOfWeek.SUNDAY).withHour(23).withMinute(59).withSecond(59);
            }
            String start = startL.format(formatter);
            String end = endL.format(formatter);
            NumberOfAlertToChartVo vo = new NumberOfAlertToChartVo();
            DateTimeFormatter formatter_for_week = DateTimeFormatter.ofPattern("MM-dd");
            vo.setNumberOfAlert(String.valueOf(super.baseService.selectListRangeByCreateTime(start,end).size()));
            vo.setDate(startL.format(formatter_for_week));
            rangeBy5Weeks.add(0,vo);
            // 将startL减去1周
            startL = startL.minusWeeks(1);
        }
        jsonObject.put("rangeBy5Weeks",rangeBy5Weeks);
        //获取近五月的预警
        startL = LocalDateTime.now();
        List<NumberOfAlertToChartVo> rangeBy5Months = new ArrayList<>();
        for (int i = 0;i < 5;i++) {
            // 格式化日期时间
            // 把startL设置当前时间减一周后的周一00:00:00
            startL = startL.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0);
            // 把endL设置成周日23:59:59，如果是当前一周，设置成当前时间
            if (i == 0) {
                endL = LocalDateTime.now();
            } else {
                endL = startL.plusMonths(1).minusDays(1).withHour(23).withMinute(59).withSecond(59);
            }
            String start = startL.format(formatter);
            String end = endL.format(formatter);
            NumberOfAlertToChartVo vo = new NumberOfAlertToChartVo();

            DateTimeFormatter formatter_for_month = DateTimeFormatter.ofPattern("MM");
            vo.setNumberOfAlert(String.valueOf(super.baseService.selectListRangeByCreateTime(start,end).size()));
            vo.setDate(startL.format(formatter_for_month));
            rangeBy5Months.add(0,vo);
            // 开始时间减去1个月
            startL = startL.minusMonths(1);
        }
        jsonObject.put("rangeBy5Months",rangeBy5Months);
        return AjaxResult.success(jsonObject);
    }

    @GetMapping("/alerts_counts_to_chart/{devId}")
    public AjaxResult rangeAlertCountsToChart(@PathVariable String devId) {
        JSONObject jsonObject = new JSONObject();
        List<Map<String, Integer>> range = new ArrayList<>();

        YearMonth currentYearMonth = YearMonth.now();
        int currentYear = currentYearMonth.getYear();
        int currentMonth = currentYearMonth.getMonthValue();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        // 遍历每个月
        for (Month month : Month.values()) {
            int monthValue = month.getValue();

            // 如果当前月份已经过去，则跳过输出
            if (monthValue > currentMonth) {
                continue;
            }
            // 获取当前月份的第一天和最后一天
            LocalDate firstDay = LocalDate.of(currentYear, month, 1);
            LocalDate lastDay = firstDay.withDayOfMonth(firstDay.lengthOfMonth());

            String start = firstDay.atStartOfDay().withHour(0).withMinute(0).withSecond(0).format(formatter);
            String end = lastDay.atStartOfDay().withHour(23).withMinute(59).withSecond(59).format(formatter);
            Map<String, Integer> map = new HashMap<>();
            map.put(monthValue+"月",super.baseService.selectListRangeByCreateTimeAndDevId(start, end, devId).size());
            range.add(map);

        }

        jsonObject.put("range",range);
        return AjaxResult.success(jsonObject);
    }
    /*
     * @Author yangkai
     * @Description //主动拉取日志操作
     * @Date 2023/5/10
     * @Param [devId, uploadType]
     * @return com.xueyi.common.core.web.result.AjaxResult
     **/
    @PostMapping("/fetch-log")
    public AjaxResult sendMqttMsgToDev(@RequestBody JSONObject json){
        String devId = json.getString("devId");
        devId = StringUtils.isEmpty(devId) ? json.getString("id") : devId;
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("devId", devId);

        mqttTemplate.sendToMqtt("/prod/digital_man"+"/"+devId+"/log_upload", jsonObject.toJSONString());
        return success("操作成功");
    }

    /**
     * 获取数字人状态事件上报日志选择框列表
     */
    @Override
    @GetMapping("/option")
    public AjaxResult option() {
        return super.option();
    }

    interface Auth {
        /** 系统 - 数字人状态事件上报日志管理 - 列表 */
        String DM_EXCEPTION_LOG_LIST = "log:log:list";
        /** 系统 - 数字人状态事件上报日志管理 - 详情 */
        String DM_EXCEPTION_LOG_SINGLE = "log:log:single";
        /** 系统 - 数字人状态事件上报日志管理 - 新增 */
        String DM_EXCEPTION_LOG_ADD = "log:log:add";
        /** 系统 - 数字人状态事件上报日志管理 - 修改 */
        String DM_EXCEPTION_LOG_EDIT = "log:log:edit";
        /** 系统 - 数字人状态事件上报日志管理 - 删除 */
        String DM_EXCEPTION_LOG_DEL = "log:log:delete";
    }
}
