package com.common.service;

import com.common.entity.DeviceCollectHeartbeat;
import com.common.entity.DeviceCollectHeartbeatHistory;
import com.common.entity.WecomNotification;
import com.common.mapper.DeviceCollectHeartbeatMapper;
import com.common.mapper.DeviceCollectHeartbeatHistoryMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 探针心跳服务
 * 管理探针心跳状态、心跳历史、以及离线告警
 */
@Service
public class ProbeHeartbeatService {

    private static final Logger logger = LoggerFactory.getLogger(ProbeHeartbeatService.class);

    @Autowired
    private DeviceCollectHeartbeatMapper heartbeatMapper;

    @Autowired
    private DeviceCollectHeartbeatHistoryMapper historyMapper;

    @Autowired
    private WecomNotificationService wecomNotificationService;

    /** 离线阈值（分钟） */
    @Value("${probe.heartbeat.offline-threshold-minutes:10}")
    private int offlineThresholdMinutes;

    /** 租户ID */
    @Value("${probe.heartbeat.tenant-id:000000}")
    private String tenantId;

    /** 已发送离线告警的探针集合（用于告警收敛） */
    private final Map<String, Boolean> alertedProbes = new ConcurrentHashMap<>();

    /**
     * 接收探针心跳
     * @param heartbeatData 心跳数据
     * @return 探针实体
     */
    @Transactional
    public DeviceCollectHeartbeat receiveHeartbeat(ProbeHeartbeatData heartbeatData) {
        String collectId = heartbeatData.getCollectId();
        LocalDateTime now = LocalDateTime.now();
        
        // 查询现有探针状态
        DeviceCollectHeartbeat existing = heartbeatMapper.selectByCollectId(collectId);
        boolean wasOffline = existing != null && "offline".equals(existing.getStatus());
        
        // 创建或更新探针状态
        DeviceCollectHeartbeat heartbeat = new DeviceCollectHeartbeat();
        heartbeat.setCollectId(collectId);
        heartbeat.setCollectName(heartbeatData.getCollectName());
        heartbeat.setDeviceIp(heartbeatData.getDeviceIp());
        heartbeat.setAppVersion(heartbeatData.getAppVersion());
        heartbeat.setLastHeartbeat(now);
        heartbeat.setHeartbeatCount(existing == null ? 1L : existing.getHeartbeatCount() + 1);
        heartbeat.setStatus("online");
        heartbeat.setFailCount(0);
        heartbeat.setUpdateTime(now);

        
        // 如果有ID则保留
        if (existing != null) {
            heartbeat.setId(existing.getId());
        }
        
        // 插入/更新主表
        heartbeatMapper.upsert(heartbeat);
        
        // 插入历史记录
        DeviceCollectHeartbeatHistory history = DeviceCollectHeartbeatHistory.fromHeartbeat(heartbeat);
        historyMapper.insert(history);
        
        // 如果从离线恢复，发送恢复通知
        if (wasOffline) {
            sendRecoveryNotification(heartbeat);
            alertedProbes.remove(collectId); // 清除告警标记
            logger.info("探针 {} 已恢复在线", collectId);
        }
        
        logger.debug("接收探针 {} 心跳，IP: {}, 版本: {}", collectId, heartbeat.getDeviceIp(), heartbeat.getAppVersion());
        
        return heartbeat;
    }

    /**
     * 获取所有探针状态
     */
    public List<DeviceCollectHeartbeat> getAllProbes() {
        return heartbeatMapper.selectAll();
    }

    /**
     * 获取在线探针
     */
    public List<DeviceCollectHeartbeat> getOnlineProbes() {
        return heartbeatMapper.selectAllOnline();
    }

    /**
     * 获取离线探针
     */
    public List<DeviceCollectHeartbeat> getOfflineProbes() {
        return heartbeatMapper.selectAllOffline();
    }

    /**
     * 根据探针ID获取状态
     */
    public DeviceCollectHeartbeat getProbeById(String collectId) {
        return heartbeatMapper.selectByCollectId(collectId);
    }

    /**
     * 检查探针状态并标记离线
     * @return 新增的离线探针列表
     */
    @Transactional
    public List<DeviceCollectHeartbeat> checkAndMarkOfflineProbes() {
        LocalDateTime thresholdTime = LocalDateTime.now().minusMinutes(offlineThresholdMinutes);
        List<DeviceCollectHeartbeat> candidates = heartbeatMapper.selectOfflineCandidates(thresholdTime);
        
        List<DeviceCollectHeartbeat> newlyOffline = new java.util.ArrayList<>();
        
        for (DeviceCollectHeartbeat probe : candidates) {
            String collectId = probe.getCollectId();
            
            // 检查是否已经发送过告警（告警收敛）
            if (alertedProbes.containsKey(collectId)) {
                // 仅更新状态，不重复告警
                heartbeatMapper.updateStatus(collectId, "offline", 
                    (probe.getFailCount() == null ? 0 : probe.getFailCount()) + 1, LocalDateTime.now());
                continue;
            }
            
            // 标记为离线
            heartbeatMapper.updateStatus(collectId, "offline", 
                (probe.getFailCount() == null ? 0 : probe.getFailCount()) + 1, LocalDateTime.now());
            
            // 发送离线告警
            sendOfflineAlert(probe);
            
            // 标记已告警
            alertedProbes.put(collectId, true);
            newlyOffline.add(probe);
            
            logger.warn("探针 {} 已离线，最后心跳时间: {}", collectId, probe.getLastHeartbeat());
        }
        
        return newlyOffline;
    }

    /**
     * 发送离线告警
     */
    private void sendOfflineAlert(DeviceCollectHeartbeat probe) {
        String content = String.format(
                "【探针离线告警】%n" +
                "探针ID: %s%n" +
                "探针名称: %s%n" +
                "探针IP: %s%n" +
                "版本: %s%n" +
                "离线时间: %s%n" +
                "最后心跳: %s%n" +
                "建议: 请检查探针服务是否正常运行",
                probe.getCollectId(),
                probe.getCollectName() != null ? probe.getCollectName() : "未知",
                probe.getDeviceIp(),
                probe.getAppVersion() != null ? probe.getAppVersion() : "未知",
                LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
                probe.getLastHeartbeat() != null ? probe.getLastHeartbeat().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : "未知"
        );
        
        try {
            WecomNotification notification = wecomNotificationService.sendAlert(
                    "探针离线-" + probe.getCollectId(),
                    "probe_offline",
                    "4", // 紧急
                    content,
                    probe.getDeviceIp()
            );
            logger.info("发送探针离线告警成功, 通知ID: {}", notification.getWecomNotificationId());
        } catch (Exception e) {
            logger.error("发送探针离线告警失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 发送恢复通知
     */
    private void sendRecoveryNotification(DeviceCollectHeartbeat probe) {
        String content = String.format(
                "【探针恢复通知】%n" +
                "探针ID: %s%n" +
                "探针名称: %s%n" +
                "探针IP: %s%n" +
                "恢复时间: %s%n" +
                "状态: 已恢复正常",
                probe.getCollectId(),
                probe.getCollectName() != null ? probe.getCollectName() : "未知",
                probe.getDeviceIp(),
                LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
        );
        
        try {
            WecomNotification notification = wecomNotificationService.sendAlert(
                    "探针恢复-" + probe.getCollectId(),
                    "probe_recovery",
                    "1", // 低
                    content,
                    probe.getDeviceIp()
            );
            logger.info("发送探针恢复通知成功, 通知ID: {}", notification.getWecomNotificationId());
        } catch (Exception e) {
            logger.error("发送探针恢复通知失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 清理历史记录
     * @param daysToKeep 保留天数
     * @return 删除的记录数
     */
    public long cleanupHistory(int daysToKeep) {
        LocalDateTime beforeTime = LocalDateTime.now().minusDays(daysToKeep);
        long count = historyMapper.countBeforeTime(beforeTime);
        if (count > 0) {
            int deleted = historyMapper.deleteBeforeTime(beforeTime);
            logger.info("清理心跳历史记录: 删除 {} 条, 保留 {} 天前的数据", deleted, daysToKeep);
            return deleted;
        }
        return 0;
    }

    /**
     * 清除指定探针的告警标记（手动恢复）
     */
    public void clearAlertFlag(String collectId) {
        alertedProbes.remove(collectId);
        logger.info("清除探针 {} 的告警标记", collectId);
    }

    /**
     * 获取离线阈值配置
     */
    public int getOfflineThresholdMinutes() {
        return offlineThresholdMinutes;
    }

    /**
     * 探针心跳数据DTO
     */
    public static class ProbeHeartbeatData {
        private String collectId;
        private String collectName;
        private String deviceIp;
        private String appVersion;
        private String loadStatus;
        
        public String getCollectId() { return collectId; }
        public void setCollectId(String collectId) { this.collectId = collectId; }
        public String getCollectName() { return collectName; }
        public void setCollectName(String collectName) { this.collectName = collectName; }
        public String getDeviceIp() { return deviceIp; }
        public void setDeviceIp(String deviceIp) { this.deviceIp = deviceIp; }
        public String getAppVersion() { return appVersion; }
        public void setAppVersion(String appVersion) { this.appVersion = appVersion; }
        public String getLoadStatus() { return loadStatus; }
        public void setLoadStatus(String loadStatus) { this.loadStatus = loadStatus; }
    }
}
