package com.common.service;


import com.common.entity.DeviceStatsDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import com.common.service.DeviceCollectTaskUpdateService;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import lombok.RequiredArgsConstructor;

@Slf4j
@Service
@Component
@RequiredArgsConstructor
public class DeviceStatsUpdateService {

    @Autowired
    private final DeviceCollectTaskUpdateService updateService;
    private static final DateTimeFormatter DATE_FORMATTER =
            DateTimeFormatter.ofPattern("yyyyMMdd");

    @Autowired
    private JdbcTemplate jdbcTemplate;

    // SQL 模板定义
    private static final String COLLECT_DEVICE_STATS_SQL =
            "WITH device_receive_stats AS ( " +
                    "    SELECT device_id, MAX(receive_time) AS last_receive_time " +
                    "    FROM %s " +
                    "    WHERE receive_time >= CURRENT_DATE " +
                    "    GROUP BY device_id " +
                    "), " +
                    "parse_stats AS ( " +
                    "    SELECT device_id, COUNT(*) AS parse_count " +
                    "    FROM ( " +
                    "        SELECT device_id FROM %s " +
                    "        WHERE created_at >= CURRENT_DATE " +
                    "        UNION ALL " +
                    "        SELECT device_id FROM %s " +
                    "        WHERE created_at >= CURRENT_DATE " +
                    "    ) t " +
                    "    GROUP BY device_id " +
                    "), " +
                    "non_log_stats AS ( " +
                    "    SELECT device_id, COUNT(*) AS non_log_count " +
                    "    FROM %s " +
                    "    WHERE created_at >= CURRENT_DATE " +
                    "    GROUP BY device_id " +
                    "), " +
                    "combined_stats AS ( " +
                    "    SELECT COALESCE(r.device_id, p.device_id, n.device_id) AS device_id, " +
                    "           r.last_receive_time, " +
                    "           COALESCE(p.parse_count, 0) AS parse_count, " +
                    "           COALESCE(n.non_log_count, 0) AS non_log_count " +
                    "    FROM device_receive_stats r " +
                    "    FULL OUTER JOIN parse_stats p ON r.device_id = p.device_id " +
                    "    FULL OUTER JOIN non_log_stats n ON COALESCE(r.device_id, p.device_id) = n.device_id " +
                    ") " +
                    "SELECT * FROM combined_stats";

    private static final String UPDATE_DEVICE_STATS_SQL =
            "UPDATE device_device " +
                    "SET last_receive_time = ?, " +
                    "    today_parse_count = ?, " +
                    "    today_non_log_count = ?, " +
                    "    updated_at = NOW() " +
                    "WHERE id = ?";

    private static final String UPDATE_DEVICE_COUNT_SQL =
            "UPDATE device_device " +
                    "SET today_parse_count = 0, " +
                    "    today_non_log_count = 0, " +
                    "    updated_at = NOW() " ;

    /**
     * 每5分钟执行一次设备统计更新（秒：0，分：*，时：*）
     */
    @Scheduled(cron = "0 */5 * * * ?")
    @Transactional
    public void updateDeviceStats() {
        long startTime = System.currentTimeMillis();
        log.info("开始执行设备统计更新任务...");

        try {
            // 获取当前日期，用于动态表名
            String today = LocalDateTime.now().format(DATE_FORMATTER);

            // 统计每个设备的当天数据
            List<DeviceStatsDTO> deviceStats = collectDeviceStats(today);

            // 批量更新 device_device 表
            batchUpdateDeviceStats(deviceStats);

            long endTime = System.currentTimeMillis();
            log.info("设备统计更新完成，处理设备数：{}，耗时：{}ms",
                    deviceStats.size(), (endTime - startTime));

            // 批量更新 device_collect_task 表
            updateDeviceCollectTaskTimes();

        } catch (Exception e) {
            log.error("设备统计更新任务执行失败", e);
            throw e;
        }
    }

    /**
     * 每天执行一次设备统计数值清零更新（秒：1，分：0，时：0）
     */
    @Scheduled(cron = "1 0 0 * * ?")
    @Transactional
    public void updateDeviceCount() {
        long startTime = System.currentTimeMillis();
        log.info("开始执行设备统计数值清零更新任务...");
        try {
            int devCount= jdbcTemplate.update(UPDATE_DEVICE_COUNT_SQL);
            long endTime = System.currentTimeMillis();
            log.info("设备统计数值清零更新完成，处理设备数：{} ，耗时：{}ms",devCount,  (endTime - startTime));

        } catch (Exception e) {
            log.error("设备统计数值清零更新任务执行失败", e);
            throw e;
        }
    }

    /**
     * 收集设备统计信息
     */
    private List<DeviceStatsDTO> collectDeviceStats(String today) {
        // 构建动态表名
        String receiveLogTable = "device_receive_log";
        String normalDataTable = "syslog_normal_data_" + today;
        String normalAlarmTable = "syslog_normal_alarm_" + today;
        String nonNormalTable = "syslog_non_normal_message_" + today;
        String sql = String.format(
                COLLECT_DEVICE_STATS_SQL,
                receiveLogTable,
                normalDataTable,
                normalAlarmTable,
                nonNormalTable
        );

        return jdbcTemplate.query(sql, new RowMapper<DeviceStatsDTO>() {
            @Override
            public DeviceStatsDTO mapRow(ResultSet rs, int rowNum) throws SQLException {
                DeviceStatsDTO dto = new DeviceStatsDTO();
                dto.setDeviceId(rs.getLong("device_id"));

                java.sql.Timestamp timestamp = rs.getTimestamp("last_receive_time");
                if (timestamp != null) {
                    dto.setLastReceiveTime(timestamp.toLocalDateTime());
                }

                dto.setParseCount(rs.getInt("parse_count"));
                dto.setNonLogCount(rs.getInt("non_log_count"));
                return dto;
            }
        });
    }

    /**
     * 批量更新设备统计信息
     */
    private void batchUpdateDeviceStats(List<DeviceStatsDTO> deviceStats) {
        if (deviceStats.isEmpty()) {
            return;
        }

        // 使用批量更新提高性能
        List<Object[]> batchArgs = deviceStats.stream()
                .map(dto -> new Object[] {
                        dto.getLastReceiveTime(),
                        dto.getParseCount(),
                        dto.getNonLogCount(),
                        dto.getDeviceId()
                })
                .collect(java.util.stream.Collectors.toList());

        int[] updateCounts = jdbcTemplate.batchUpdate(UPDATE_DEVICE_STATS_SQL, batchArgs);

        log.debug("批量更新完成，影响行数：{}", updateCounts.length);
    }


    public void updateDeviceCollectTaskTimes() {
        log.info("开始执行设备采集探针任务时间更新，时间: {}", LocalDateTime.now());

        try {
            long startTime = System.currentTimeMillis();

            // 使用批量更新方法
            updateService.batchUpdateDeviceTaskTimes();
            long endTime = System.currentTimeMillis();
            log.info("设备采集探针任务时间更新完成，耗时: {}ms", endTime - startTime);

        } catch (Exception e) {
            log.error("执行设备采集探针任务时间更新失败", e);
        }
    }
}