package com.gameplatform.server.service.detection;

import com.gameplatform.server.mapper.agent.LinkTaskMapper;
import com.gameplatform.server.model.entity.agent.LinkTask;
import com.gameplatform.server.model.entity.detection.GameCompletionLog;
import com.gameplatform.server.service.cooldown.MemoryMachineCooldownService;
import com.gameplatform.server.mapper.detection.GameCompletionLogMapper;
import com.gameplatform.server.mapper.history.LinkTaskStatusHistoryMapper;
import com.gameplatform.server.model.entity.history.LinkTaskStatusHistory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 游戏完成检测服务 - 改进版
 * 
 * 解决问题：
 * 1. 避免误判刚登录为完成状态
 * 2. 增加确认机制，提高准确性
 * 3. 记录检测日志，便于问题排查
 */
@Service
public class GameCompletionDetectionService {
    
    private static final Logger log = LoggerFactory.getLogger(GameCompletionDetectionService.class);
    
    // 登录后的缓冲时间（秒），在此时间内不检测完成状态
    private static final int LOGIN_BUFFER_SECONDS = 30;
    
    // 完成确认的最小间隔时间（秒）
    private static final int COMPLETION_CONFIRMATION_INTERVAL_SECONDS = 10;
    
    private final LinkTaskMapper linkTaskMapper;
    private final MemoryMachineCooldownService machineCooldownService;
    private final GameCompletionLogMapper gameCompletionLogMapper;
    private final LinkTaskStatusHistoryMapper statusHistoryMapper;
    
    // 待确认的完成检测：machineId -> 检测时间
    private final ConcurrentMap<String, LocalDateTime> pendingCompletions = new ConcurrentHashMap<>();
    
    // 最近登录时间缓存：machineId -> 登录时间
    private final ConcurrentMap<String, LocalDateTime> recentLogins = new ConcurrentHashMap<>();
    
    public GameCompletionDetectionService(LinkTaskMapper linkTaskMapper, 
                                        MemoryMachineCooldownService machineCooldownService,
                                        GameCompletionLogMapper gameCompletionLogMapper,
                                        LinkTaskStatusHistoryMapper statusHistoryMapper) {
        this.linkTaskMapper = linkTaskMapper;
        this.machineCooldownService = machineCooldownService;
        this.gameCompletionLogMapper = gameCompletionLogMapper;
        this.statusHistoryMapper = statusHistoryMapper;
    }
    
    /**
     * 检测设备游戏完成状态
     * @param machineId 设备ID
     * @param deviceStatus 设备状态
     * @param detectionSource 检测来源
     * @return 是否检测到完成
     */
    @Transactional
    public boolean detectGameCompletion(String machineId, String deviceStatus, String detectionSource) {
        if (machineId == null || machineId.trim().isEmpty()) {
            return false;
        }
        
        // 查找该设备上的 LOGGED_IN 状态任务
        List<LinkTask> loggedInTasks = linkTaskMapper.findByMachineIdAndStatus(machineId, "LOGGED_IN");
        if (loggedInTasks.isEmpty()) {
//            log.debug("设备{}没有LOGGED_IN状态的任务，跳过完成检测", machineId);
            return false;
        }
        
        // 检查是否在登录缓冲期内
        if (isInLoginBuffer(machineId)) {
            log.debug("设备{}在登录缓冲期内，跳过完成检测", machineId);
            return false;
        }
        
        // 解析设备状态，判断完成置信度
        CompletionDetectionResult result = analyzeDeviceStatus(deviceStatus, detectionSource);
        
        if (result.confidence == CompletionConfidence.LOW) {
            log.debug("设备{}完成检测置信度低，跳过处理", machineId);
            return false;
        }
        
        // 记录检测日志
        for (LinkTask task : loggedInTasks) {
            recordDetectionLog(task.getId(), machineId, detectionSource, deviceStatus, 
                             result.points, result.confidence.name());
        }
        
        // 根据置信度决定处理策略
        if (result.confidence == CompletionConfidence.HIGH) {
            // 高置信度直接标记完成
            return markTasksCompleted(loggedInTasks, machineId, result.points, detectionSource);
        } else {
            // 中等置信度需要确认：首次记录待确认，等待下一次同状态触发且间隔足够再完成
            return scheduleCompletionConfirmation(machineId, loggedInTasks, result, detectionSource);
        }
    }
    
    /**
     * 记录设备登录时间
     */
    public void recordDeviceLogin(String machineId) {
        if (machineId != null && !machineId.trim().isEmpty()) {
            recentLogins.put(machineId, LocalDateTime.now());
            log.debug("记录设备{}登录时间", machineId);
        }
    }
    
    /**
     * 检查是否在登录缓冲期内
     */
    private boolean isInLoginBuffer(String machineId) {
        LocalDateTime loginTime = recentLogins.get(machineId);
        if (loginTime == null) {
            return false;
        }
        
        LocalDateTime bufferEndTime = loginTime.plusSeconds(LOGIN_BUFFER_SECONDS);
        boolean inBuffer = LocalDateTime.now().isBefore(bufferEndTime);
        
        if (!inBuffer) {
            // 缓冲期结束，清理记录
            recentLogins.remove(machineId);
        }
        
        return inBuffer;
    }
    
    /**
     * 分析设备状态，确定完成检测结果
     */
    private CompletionDetectionResult analyzeDeviceStatus(String deviceStatus, String detectionSource) {
        CompletionDetectionResult result = new CompletionDetectionResult();
        
        if ("已打完".equals(deviceStatus)) {
            result.confidence = CompletionConfidence.HIGH;
            result.points = null;
        } else if ("空闲".equals(deviceStatus)) {
            // 空闲状态的置信度取决于检测来源
            if ("MANUAL".equals(detectionSource) || "REGION_SELECT".equals(detectionSource)) {
                result.confidence = CompletionConfidence.MEDIUM;
            } else {
                result.confidence = CompletionConfidence.LOW;
            }
            result.points = null;
        } else if (deviceStatus != null && deviceStatus.matches("\\d+")) {
            // 数字点数，表示游戏进行中，不是完成状态
            result.confidence = CompletionConfidence.LOW;
            result.points = Integer.parseInt(deviceStatus);
        } else {
            result.confidence = CompletionConfidence.LOW;
            result.points = null;
        }
        
        return result;
    }
    
    /**
     * 安排完成确认
     */
    private boolean scheduleCompletionConfirmation(String machineId, List<LinkTask> tasks, 
                                                 CompletionDetectionResult result, String detectionSource) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime lastPending = pendingCompletions.get(machineId);
        
        if (lastPending == null) {
            pendingCompletions.put(machineId, now);
            log.info("设备{}游戏完成检测待确认，首次记录，等待{}秒后再次确认", machineId, COMPLETION_CONFIRMATION_INTERVAL_SECONDS);
            com.gameplatform.server.util.AuditLogger.info("CompletionPending: device={}, source={}, interval={}s", machineId, detectionSource, COMPLETION_CONFIRMATION_INTERVAL_SECONDS);
            return false;
        }
        if (now.isBefore(lastPending.plusSeconds(COMPLETION_CONFIRMATION_INTERVAL_SECONDS))) {
            log.debug("设备{}完成确认间隔太短，跳过", machineId);
            return false;
        }
        // 到达确认时间窗口，进行最终标记
        boolean res = markTasksCompleted(tasks, machineId, result.points, detectionSource + "_CONFIRMED");
        pendingCompletions.remove(machineId);
        return res;
    }
    
    /**
     * 标记任务为完成状态
     */
    private boolean markTasksCompleted(List<LinkTask> tasks, String machineId, 
                                     Integer points, String detectionSource) {
        boolean anyCompleted = false;
        LocalDateTime now = LocalDateTime.now();
        
        for (LinkTask task : tasks) {
            try {
                task.setStatus("COMPLETED");
                task.setUpdatedAt(now);
                // 正常检测完成：记录原因
                task.setReason("状态：已完成");
                
                // 设置完成点数
                if (points != null) {
                    task.setCompletedPoints(points);
                } else if (task.getCompletedPoints() == null) {
                    task.setCompletedPoints(0);
                }
                
                String prev = task.getStatus();
                int updated = linkTaskMapper.update(task);
                if (updated > 0) {
                    log.info("任务{}已标记完成：设备={}，点数={}，检测来源={}", 
                            task.getCodeNo(), machineId, task.getCompletedPoints(), detectionSource);
                    com.gameplatform.server.util.AuditLogger.info("StatusTransition: codeNo={}, device={}, {}->COMPLETED, source={}, points={}",
                            task.getCodeNo(), machineId, prev, detectionSource, task.getCompletedPoints());
                    try {
                        if (statusHistoryMapper != null) {
                            statusHistoryMapper.insert(new LinkTaskStatusHistory(
                                    task.getId(), task.getCodeNo(), machineId, prev, "COMPLETED", detectionSource,
                                    "detectionComplete", null, null
                            ));
                        }
                    } catch (Exception ignore) {}
                    anyCompleted = true;
                    
                    // 将设备加入冷却队列
                    machineCooldownService.addMachineToCooldown(machineId, 
                        "游戏完成 - " + detectionSource, task.getId());
                } else {
                    log.warn("更新任务{}完成状态失败", task.getCodeNo());
                }
                
            } catch (Exception e) {
                log.error("标记任务{}完成时发生异常", task.getCodeNo(), e);
            }
        }
        
        if (anyCompleted) {
            // 清理待确认记录
            pendingCompletions.remove(machineId);
            // 清理登录记录
            recentLogins.remove(machineId);
        }
        
        return anyCompleted;
    }
    
    /**
     * 记录检测日志
     */
    private void recordDetectionLog(Long linkTaskId, String machineId, String detectionSource,
                                  String deviceStatus, Integer points, String confidence) {
        try {
            GameCompletionLog rec = new GameCompletionLog(
                linkTaskId, machineId, detectionSource, deviceStatus, points, confidence);
            if (gameCompletionLogMapper != null) {
                gameCompletionLogMapper.insert(rec);
            }
            com.gameplatform.server.util.AuditLogger.info("CompletionDetect: taskId={}, device={}, source={}, status={}, points={}, confidence={}",
                    linkTaskId, machineId, detectionSource, deviceStatus, points, confidence);
        } catch (Exception e) {
            this.log.error("记录游戏完成检测日志失败", e);
        }
    }
    
    /**
     * 清理过期的待确认记录
     */
    public void cleanupExpiredPendingCompletions() {
        LocalDateTime expireTime = LocalDateTime.now().minusMinutes(5);
        
        pendingCompletions.entrySet().removeIf(entry -> 
            entry.getValue().isBefore(expireTime));
            
        recentLogins.entrySet().removeIf(entry -> 
            entry.getValue().isBefore(expireTime));
    }
    
    /**
     * 完成检测结果
     */
    private static class CompletionDetectionResult {
        CompletionConfidence confidence;
        Integer points;
    }
    
    /**
     * 完成置信度枚举
     */
    private enum CompletionConfidence {
        HIGH,    // 高置信度：明确的"已打完"状态
        MEDIUM,  // 中等置信度：可信来源的"空闲"状态
        LOW      // 低置信度：不可信的状态变化
    }
}

