package com.gameplatform.server.service.link;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.gameplatform.server.mapper.agent.LinkTaskMapper;
import com.gameplatform.server.model.dto.device.DeviceStatusResponse;
import com.gameplatform.server.model.entity.agent.LinkTask;
import com.gameplatform.server.event.DeviceStatusUpdatedEvent;
import com.gameplatform.server.service.detection.GameCompletionDetectionService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.context.event.EventListener;
import org.springframework.dao.CannotAcquireLockException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 设备任务更新服务 - 改进版
 * 负责根据设备状态更新对应的链接任务
 * 
 * 改进点：
 * 1. 使用新的游戏完成检测服务
 * 2. 避免误判刚登录为完成状态
 * 3. 增加检测置信度机制
 */
@Service
public class DeviceTaskUpdateService {
    private static final Logger log = LoggerFactory.getLogger(DeviceTaskUpdateService.class);
    
    private final LinkTaskMapper linkTaskMapper;
    private final ObjectMapper objectMapper;
    private final GameCompletionDetectionService completionDetectionService;
    
    public DeviceTaskUpdateService(LinkTaskMapper linkTaskMapper, 
                                 ObjectMapper objectMapper,
                                 GameCompletionDetectionService completionDetectionService) {
        this.linkTaskMapper = linkTaskMapper;
        this.objectMapper = objectMapper;
        this.completionDetectionService = completionDetectionService;
    }
    
    /**
     * 根据设备状态信息更新链接任务 - 改进版
     * @param deviceInfo 设备状态信息
     */
    public void updateTaskByDeviceStatus(DeviceStatusResponse.DeviceInfo deviceInfo) {
        String deviceId = deviceInfo.getDeviceId();
        String val = deviceInfo.getVal();
        
//        log.debug("开始处理设备 {} 的状态更新: val={}, available={}",
//                deviceId, val, deviceInfo.isAvailable());
        
        // 使用改进的游戏完成检测服务
        boolean completionDetected = completionDetectionService.detectGameCompletion(
            deviceId, val, "EVENT_LISTENER");
        
        if (completionDetected) {
            log.info("设备 {} 游戏完成检测成功，状态：{}", deviceId, val);
        }
        
        // 处理数字点数更新（游戏进行中）
        if (val != null && val.matches("\\d+")) {
            updateTaskPointsOnly(deviceId, Integer.parseInt(val));
        }
    }
    
    /**
     * 仅更新任务点数（不改变状态）- 带重试机制
     */
    private void updateTaskPointsOnly(String deviceId, Integer points) {
        List<LinkTask> loggedInTasks = linkTaskMapper.findByMachineIdAndStatus(deviceId, "LOGGED_IN");
        
        for (LinkTask task : loggedInTasks) {
            try {
                updateSingleTaskPoints(task, points, 3); // 最多重试3次
            } catch (Exception e) {
                log.error("更新任务 {} 点数时发生异常，跳过该任务继续处理其他任务", task.getCodeNo(), e);
                // 继续处理其他任务，不因单个任务失败而中断
            }
        }
    }
    
    /**
     * 更新单个任务点数，带重试机制
     */
    private void updateSingleTaskPoints(LinkTask task, Integer points, int maxRetries) {
        for (int attempts = 1; attempts <= maxRetries; attempts++) {
            try {
                updateTaskPointsTransaction(task, points);
                return; // 成功则退出
            } catch (CannotAcquireLockException e) {
                log.warn("任务 {} 更新时遇到锁等待超时，重试次数: {}/{}", 
                        task.getCodeNo(), attempts, maxRetries);
                
                if (attempts >= maxRetries) {
                    log.error("任务 {} 点数更新失败，已达到最大重试次数", task.getCodeNo());
                    throw e; // 重新抛出异常让上层处理
                }
                
                // 短暂等待后重试
                try {
                    long jitter = (long) (Math.random() * 50L);
                    Thread.sleep(100L * attempts + jitter); // 递增 + 抖动
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("重试被中断", ie);
                }
                
            } catch (Exception e) {
                log.error("更新任务 {} 点数时发生异常", task.getCodeNo(), e);
                throw e; // 其他异常直接抛出
            }
        }
    }
    
    /**
     * 在事务中更新任务点数
     */
    @Transactional(timeout = 10)
    private void updateTaskPointsTransaction(LinkTask task, Integer points) {
        // 仅当点数更大时才更新，减少写锁争用
        int updated = linkTaskMapper.updatePointsIfGreater(task.getId(), points);
        if (updated > 0) {
            log.debug("任务 {} 点数已更新为: {}", task.getCodeNo(), points);
        } else {
            log.debug("任务 {} 点数未更新（新值不大于现有值或记录已变更）", task.getCodeNo());
        }
    }
    
    // 保留原方法以兼容现有代码，但标记为已弃用
    
    /**
     * @deprecated 使用 GameCompletionDetectionService 替代
     */
    @Deprecated
    private void handleCompletedTasks(List<LinkTask> tasks, String deviceId) {
        log.warn("使用已弃用的 handleCompletedTasks 方法，建议使用 GameCompletionDetectionService");
        // 这些方法保留但不推荐使用
    }
    
    /**
     * @deprecated 使用 GameCompletionDetectionService 替代
     */
    @Deprecated
    private void updateTaskAsCompleted(LinkTask task) {
        log.warn("使用已弃用的 updateTaskAsCompleted 方法");
    }
    
    /**
     * @deprecated 使用 GameCompletionDetectionService 替代
     */
    @Deprecated
    private void handleIdleTasks(List<LinkTask> tasks, String deviceId) {
        log.warn("使用已弃用的 handleIdleTasks 方法");
    }
    
    /**
     * @deprecated 使用 updateTaskPointsOnly 替代
     */
    @Deprecated
    private void updateTaskPoints(List<LinkTask> tasks, Integer points) {
        log.warn("使用已弃用的 updateTaskPoints 方法");
    }
    
    /**
     * 批量处理设备状态更新 - 优化版本
     * 移除大事务，改为单个设备独立处理以避免锁等待超时
     * @param deviceStatus 设备状态响应
     */
    public void batchUpdateTasksByDeviceStatus(DeviceStatusResponse deviceStatus) {
        log.debug("开始批量处理设备状态更新，设备数量: {}", deviceStatus.getTotalDevices());
        
        // 移除 @Transactional 注解，让每个设备独立处理
        for (DeviceStatusResponse.DeviceInfo deviceInfo : deviceStatus.getDevices().values()) {
            try {
                // 每个设备状态更新都是独立的小事务
                updateTaskByDeviceStatus(deviceInfo);
            } catch (Exception e) {
                log.error("处理设备 {} 状态更新时发生异常", deviceInfo.getDeviceId(), e);
                // 继续处理其他设备，不因单个设备失败而中断整个批次
            }
        }
        
        log.debug("批量设备状态更新处理完成");
    }
    
    /**
     * 监听设备状态更新事件 - 优化版本
     * 移除事务注解，避免长事务导致的锁等待
     * @param event 设备状态更新事件
     */
    @EventListener
    public void handleDeviceStatusUpdatedEvent(DeviceStatusUpdatedEvent event) {
        log.debug("收到设备状态更新事件，开始处理任务更新");
        try {
            batchUpdateTasksByDeviceStatus(event.getDeviceStatus());
        } catch (Exception e) {
            log.error("处理设备状态更新事件时发生异常", e);
        }
    }
}
