package com.ssyf.task.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.ssyf.module.robot.domain.entity.RConfigRelation;
import com.ssyf.module.robot.domain.entity.RRobotAccount;
import com.ssyf.module.robot.domain.entity.RRunningConfig;
import com.ssyf.module.robot.helper.ConfigTimeHelper;
import com.ssyf.third.bmiss.model.*;
import com.ssyf.third.bmiss.services.BusinessService;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * 直播间驻留监控服务 (Watchdog)
 * 专门负责管理“已在直播间内”的机器人。
 * 职责：
 * 1. 精确控制停留时长（秒级误差）。
 * 2. 高频触发互动（聊天/送礼），不受主调度器5分钟冷却限制。
 * 3. 超时后执行退出，并通知资源管理器进入冷却。
 */
@Slf4j
@Service
public class LiveRoomMonitorService {

    @Autowired @Lazy private LiveRoomActionService actionService;
    @Autowired @Lazy private RobotResourceManager resourceManager;
    @Autowired @Lazy private RobotSessionManager sessionManager;
    @Autowired @Lazy private BusinessService businessService; // 新增注入
    @Autowired @Lazy private RobotManualControlService manualControlService; // 新增手动控制服务
    @Autowired @Lazy private LiveRoomStatusMonitorService liveRoomStatusMonitorService; // 新增直播间状态监听服务

    // 在线机器人注册表: Key=RobotUuid
    private final Map<String, RobotMonitorContext> monitoringRobots = new ConcurrentHashMap<>();

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // 直播间状态缓存相关常量
    private static final String LIVE_ROOM_INFO_CACHE_PREFIX = "live:room:info:";
    private static final long LIVE_ROOM_INFO_CACHE_TIME = 10;
    
    // 机器人监控状态缓存相关常量
    private static final String ROBOT_MONITOR_STATUS_PREFIX = "robot:monitor:status:";
    private static final String ROBOT_MONITOR_ROOMS_KEY = "robot:monitor:active:rooms";
    private static final long ROBOT_MONITOR_CACHE_TIME = 24 * 60 * 60; // 24小时

    /**
     * 将机器人注册到监控服务 (在进入直播间成功后调用)
     */
    public void register(RRobotAccount account, LiveRoom room, RConfigRelation relation, 
                         RRunningConfig config, UserInfo userInfo, long planExitTimestamp) {
        
        RobotMonitorContext context = new RobotMonitorContext(
                account, room, relation, config, userInfo, planExitTimestamp
        );
        monitoringRobots.put(account.getUuid(), context);
        
        // 将直播间添加到状态监控服务
        liveRoomStatusMonitorService.addRoomToMonitor(room.getUser_id());
        
        // 缓存机器人监控状态
        cacheRobotStatus(account.getUuid(), context);
        
        log.debug("机器人加入驻留监控: Account={}, RoomId={}, PlanExit={}", 
                account.getEmail(), room.getUser_id(), planExitTimestamp);
    }

    /**
     * 检查机器人是否正在监控中 (用于资源管理器过滤)
     */
    public boolean isMonitoring(String robotUuid) {
        return monitoringRobots.containsKey(robotUuid);
    }

    @Scheduled(fixedDelay = 15000)
    public void monitorTick() {
        if (monitoringRobots.isEmpty()) { return; }

        long now = System.currentTimeMillis();
        Iterator<Map.Entry<String, RobotMonitorContext>> it = monitoringRobots.entrySet().iterator();

        while (it.hasNext()) {
            Map.Entry<String, RobotMonitorContext> entry = it.next();
            String uuid = entry.getKey();
            RobotMonitorContext ctx = entry.getValue();

            try {
                // ============================================================
                // 解决问题 2：动态配置更新 (Hot Reload)
                // ============================================================
                // 从 ResourceManager 获取内存中最新的配置（ResourceManager 已有 DB 同步机制）
                RConfigRelation latestRelation = resourceManager.getRelation(uuid);
                RRunningConfig latestConfig = (latestRelation != null)
                        ? resourceManager.getConfig(latestRelation.getConfigUuid()) : null;

                // 如果配置被删除或禁用，强制退出
                if (latestRelation == null || latestConfig == null || Integer.valueOf(0).equals(latestConfig.getStatus())) {
                    log.debug("配置已失效或被禁用，执行退出: {}", ctx.getAccount().getEmail());
                    performExit(ctx);
                    it.remove();
                    continue;
                }

                // ============================================================
                // 【新增核心逻辑】检查是否被手动控制
                // ============================================================
                // 如果机器人被运营手动接管，立即退出监控并释放控制权
                if (manualControlService.isManuallyControlled(uuid)) {
                    log.info("机器人被手动接管，退出监控: Robot={}, Room={}", 
                            ctx.getAccount().getEmail(), ctx.getRoom().getUser_id());
                    // it.remove(); // 从监控列表中移除，但不执行退出逻辑（保持当前状态）
                    continue;
                }

                // 更新 Context 中的配置引用，确保互动概率、送礼策略实时生效
                ctx.setRelation(latestRelation);
                ctx.setConfig(latestConfig);

                // ============================================================
                // 解决问题 3：有效时间段动态检测
                // ============================================================
                // 每次 tick 都检查当前时间是否还在配置的允许运行时间段内
                if (!ConfigTimeHelper.isInValidTime(latestRelation)) {
                    log.debug("当前时间不在配置的有效运行时间段内，强制退出: {}", ctx.getAccount().getEmail());
                    performExit(ctx); // 执行退出直播间 + 登出逻辑
                    it.remove();
                    continue;
                }

                // ============================================================
                // 原有逻辑：检查停留时长
                // ============================================================
                if (now >= ctx.getPlanExitTimestamp()) {
                    log.debug("机器人停留时间结束，执行退出: {}", ctx.getAccount().getEmail());
                    performExit(ctx);
                    it.remove();
                    continue;
                }

                // 获取 Session
                LoginResponse session = sessionManager.getOrRefreshSession(ctx.getAccount());
                if (session == null) {
                    it.remove();
                    resourceManager.reportFailure(uuid);
                    continue;
                }

                // ============================================================
                // 直播间关闭检测已剥离到独立的LiveRoomStatusMonitorService
                // 该服务会定时检查直播间状态，并在检测到关闭时调用quitAllRobotsInRoom方法
                // ============================================================

                // 执行互动
                actionService.executeInRoomInteraction(
                        ctx.getRoom(), ctx.getAccount(), ctx.getRelation(),
                        ctx.getConfig(), ctx.getUserInfo(), session.getToken()
                );

            } catch (Exception e) {
                log.error("监控任务异常: {}", uuid, e);
                it.remove();
                resourceManager.reportFailure(uuid);
            }
        }
    }




    /**
     * 执行退出流程
     */
    private void performExit(RobotMonitorContext ctx) {
        try {
            LoginResponse session = sessionManager.getOrRefreshSession(ctx.getAccount());
            String token = (session != null) ? session.getToken() : null;

            // 调用退出接口
            actionService.quitLiveRoom(
                    ctx.getRoom(), ctx.getAccount(), ctx.getRelation(), 
                    ctx.getConfig(), ctx.getUserInfo(), token
            );
        } finally {
            // 【关键】通知资源管理器：任务真正结束了，开始计算冷却时间
            resourceManager.markFinished(ctx.getAccount().getUuid());
            
            // 清理机器人监控状态缓存
            clearRobotStatusCache(ctx.getAccount().getUuid());
        }
    }

    /**
     * 退出指定直播间的所有机器人
     * 
     * @param roomId 直播间ID
     */
    public void quitAllRobotsInRoom(Integer roomId) {
        if (roomId == null) {
            return;
        }

        log.info("开始退出直播间所有机器人，roomId: {}", roomId);
        
        Iterator<Map.Entry<String, RobotMonitorContext>> it = monitoringRobots.entrySet().iterator();
        int quitCount = 0;
        
        while (it.hasNext()) {
            Map.Entry<String, RobotMonitorContext> entry = it.next();
            RobotMonitorContext ctx = entry.getValue();
            
            // 检查是否在目标直播间
            if (ctx.getRoom().getUser_id().equals(roomId)) {
                try {
                    performExit(ctx);
                    it.remove();
                    quitCount++;
                    log.debug("机器人退出直播间成功，robot: {}, roomId: {}", 
                            ctx.getAccount().getEmail(), roomId);
                } catch (Exception e) {
                    log.error("机器人退出直播间异常，robot: {}, roomId: {}", 
                            ctx.getAccount().getEmail(), roomId, e);
                }
            }
        }
        
        log.info("直播间机器人退出完成，roomId: {}, 退出数量: {}", roomId, quitCount);
    }

    /**
     * 缓存机器人监控状态
     * 
     * @param robotUuid 机器人UUID
     * @param context 监控上下文
     */
    private void cacheRobotStatus(String robotUuid, RobotMonitorContext context) {
        if (robotUuid == null || context == null) {
            return;
        }

        try {
            String cacheKey = ROBOT_MONITOR_STATUS_PREFIX + robotUuid;
            String contextJson = JSONUtil.toJsonStr(context);
            
            // 缓存机器人状态
            redisTemplate.opsForValue().set(cacheKey, contextJson, ROBOT_MONITOR_CACHE_TIME, TimeUnit.SECONDS);
            
            // 记录活跃直播间
            Integer roomId = context.getRoom().getUser_id();
            redisTemplate.opsForSet().add(ROBOT_MONITOR_ROOMS_KEY, String.valueOf(roomId));
            redisTemplate.expire(ROBOT_MONITOR_ROOMS_KEY, ROBOT_MONITOR_CACHE_TIME, TimeUnit.SECONDS);
            
            log.debug("机器人监控状态已缓存，robot: {}, roomId: {}", robotUuid, roomId);
        } catch (Exception e) {
            log.error("缓存机器人监控状态异常，robot: {}", robotUuid, e);
        }
    }

    /**
     * 清理机器人监控状态缓存
     * 
     * @param robotUuid 机器人UUID
     */
    private void clearRobotStatusCache(String robotUuid) {
        if (robotUuid == null) {
            return;
        }

        try {
            String cacheKey = ROBOT_MONITOR_STATUS_PREFIX + robotUuid;
            redisTemplate.delete(cacheKey);
            log.debug("机器人监控状态缓存已清理，robot: {}", robotUuid);
        } catch (Exception e) {
            log.error("清理机器人监控状态缓存异常，robot: {}", robotUuid, e);
        }
    }

    /**
     * 启动时重建监控状态
     * 从缓存中恢复已进入直播间的机器人状态
     */
    @javax.annotation.PostConstruct
    public void rebuildMonitoringStatus() {
        log.info("开始重建机器人监控状态...");
        
        try {
            // 获取所有活跃直播间
            Set<Object> activeRooms = redisTemplate.opsForSet().members(ROBOT_MONITOR_ROOMS_KEY);
            if (activeRooms == null || activeRooms.isEmpty()) {
                log.info("没有需要重建的机器人监控状态");
                return;
            }

            int rebuildCount = 0;
            
            // 扫描所有机器人状态缓存
            Set<String> cacheKeys = redisTemplate.keys(ROBOT_MONITOR_STATUS_PREFIX + "*");
            if (cacheKeys != null) {
                for (String cacheKey : cacheKeys) {
                    try {
                        Object cachedValue = redisTemplate.opsForValue().get(cacheKey);
                        if (cachedValue instanceof String) {
                            RobotMonitorContext context = JSONUtil.toBean((String) cachedValue, RobotMonitorContext.class);
                            
                            if (context != null && isValidContext(context)) {
                                // 提取机器人UUID
                                String robotUuid = cacheKey.substring(ROBOT_MONITOR_STATUS_PREFIX.length());
                                
                                // 重建监控状态
                                monitoringRobots.put(robotUuid, context);
                                
                                // 将直播间重新添加到状态监控服务
                                liveRoomStatusMonitorService.addRoomToMonitor(context.getRoom().getUser_id());
                                
                                rebuildCount++;
                                log.debug("机器人监控状态重建成功，robot: {}, roomId: {}", 
                                        robotUuid, context.getRoom().getUser_id());
                            }
                        }
                    } catch (Exception e) {
                        log.error("重建机器人监控状态异常，cacheKey: {}", cacheKey, e);
                    }
                }
            }
            
            log.info("机器人监控状态重建完成，成功重建数量: {}", rebuildCount);
            
        } catch (Exception e) {
            log.error("重建机器人监控状态异常", e);
        }
    }

    /**
     * 验证监控上下文是否有效
     * 
     * @param context 监控上下文
     * @return true表示有效，false表示无效
     */
    private boolean isValidContext(RobotMonitorContext context) {
        if (context == null) {
            return false;
        }
        
        // 检查必要字段是否存在
        if (context.getAccount() == null || context.getRoom() == null || 
            context.getRelation() == null || context.getConfig() == null || 
            context.getUserInfo() == null) {
            return false;
        }
        
        // 检查计划退出时间是否已过期（超过当前时间24小时）
        long now = System.currentTimeMillis();
        if (context.getPlanExitTimestamp() > 0 && 
            context.getPlanExitTimestamp() < now - (24 * 60 * 60 * 1000L)) {
            return false;
        }
        
        return true;
    }

    /**
     * 清理所有监控 (重置时调用)
     */
    public void clear() {
        monitoringRobots.clear();
    }

    // --- 内部上下文对象 ---
    @Data
    @AllArgsConstructor
    private static class RobotMonitorContext {
        private RRobotAccount account;
        private LiveRoom room;
        private RConfigRelation relation;
        private RRunningConfig config;
        private UserInfo userInfo;
        private long planExitTimestamp;
        private long lastCheckTime; // 新增字段
        // 构造补充
        public RobotMonitorContext(RRobotAccount account, LiveRoom room, RConfigRelation relation,
                                   RRunningConfig config, UserInfo userInfo, long planExitTimestamp) {
            this.account = account;
            this.room = room;
            this.relation = relation;
            this.config = config;
            this.userInfo = userInfo;
            this.planExitTimestamp = planExitTimestamp;
            this.lastCheckTime = System.currentTimeMillis();
        }
        
        // 无参构造器，用于JSON反序列化
        public RobotMonitorContext() {
        }
    }
}