package com.ssyf.task.service;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.ssyf.third.bmiss.model.ApiResponse;
import com.ssyf.third.bmiss.model.LiveRoom;
import com.ssyf.third.bmiss.model.UserInfo;
import com.ssyf.third.bmiss.services.BusinessService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * ASR语音解析管理服务类
 * 基于用户信息的去重管理，确保全局微服务对同一个直播间的调用只能进行一次
 * 
 * @author system
 * @since 1.0
 */
@Slf4j
@Service
public class AsrSpeechManagerService {

    @Autowired
    private BusinessService businessService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    // Redis Key前缀：ASR直播间用户集合 (asr:speech:users:{roomId})
    private static final String REDIS_PREFIX_ASR_USERS = "asr:speech:users:";
    
    // Redis Key前缀：ASR直播间信息 (asr:speech:info:{roomId})
    private static final String REDIS_PREFIX_ASR_INFO = "asr:speech:info:";
    
    // 分布式锁Key前缀
    private static final String LOCK_ASR_PREFIX = "lock:asr:speech:";
    
    // 缓存过期时间（24小时）
    private static final long CACHE_EXPIRE_HOURS = 24;

    /**
     * 开启ASR解析
     * 
     * @param roomId 直播间ID
     * @param userInfo 用户信息
     * @param room 直播间对象（可为空）
     * @return true表示成功开启或已开启，false表示开启失败
     */
    public boolean startAsr(Integer roomId, UserInfo userInfo, LiveRoom room) {
        if (roomId == null || userInfo == null || StrUtil.isBlank(userInfo.getUser_id())) {
            log.warn("开启ASR解析失败：参数不完整，roomId={}, userInfo={}", roomId, userInfo);
            return false;
        }

        String lockKey = LOCK_ASR_PREFIX + roomId;
        RLock lock = redissonClient.getLock(lockKey);
        
        boolean isLocked = false;
        try {
            // 尝试获取分布式锁，等待时间3秒，锁有效期10秒
            isLocked = lock.tryLock(3, 10, TimeUnit.SECONDS);
            if (!isLocked) {
                log.warn("获取ASR解析锁失败，直播间ID: {}", roomId);
                return false;
            }

            // 获取当前直播间用户集合
            String usersKey = REDIS_PREFIX_ASR_USERS + roomId;
            Set<String> currentUsers = getAsrUsers(usersKey);
            
            // 添加当前用户（去重处理）
            boolean isNewUser = currentUsers.add(userInfo.getUser_id());
            
            // 如果是第一个进入的用户，需要开启ASR解析
            if (currentUsers.size() == 1 && isNewUser) {
                log.info("首次开启ASR解析，直播间ID: {}, 用户ID: {}", roomId, userInfo.getUser_id());
                
                // 调用业务服务开启ASR解析
                ApiResponse response = businessService.startAsr(roomId);
                if (response != null && response.getCode() == 200) {
                    // 保存用户集合
                    saveAsrUsers(usersKey, currentUsers);
                    
                    // 保存直播间信息（如果有）
                    if (room != null) {
                        saveAsrInfo(roomId, room);
                    }
                    
                    log.info("ASR解析开启成功，直播间ID: {}, 用户ID: {}", roomId, userInfo.getUser_id());
                    return true;
                } else {
                    log.error("ASR解析开启失败，直播间ID: {}, 响应: {}", roomId, response);
                    return false;
                }
            } else {
                // 已经有其他用户开启了ASR解析，只需更新用户集合
                saveAsrUsers(usersKey, currentUsers);
                log.debug("更新ASR解析用户集合，直播间ID: {}, 当前用户数: {}, 新增用户: {}", 
                         roomId, currentUsers.size(), isNewUser);
                return true;
            }

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("开启ASR解析时线程被中断，直播间ID: {}", roomId, e);
            return false;
        } catch (Exception e) {
            log.error("开启ASR解析异常，直播间ID: {}", roomId, e);
            return false;
        } finally {
            if (isLocked && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 结束ASR解析
     * 
     * @param roomId 直播间ID
     * @param userInfo 用户信息
     * @param room 直播间对象（可为空）
     * @return true表示成功结束或已结束，false表示结束失败
     */
    public boolean endAsr(Integer roomId, UserInfo userInfo, LiveRoom room) {
        if (roomId == null || userInfo == null || StrUtil.isBlank(userInfo.getUser_id())) {
            log.warn("结束ASR解析失败：参数不完整，roomId={}, userInfo={}", roomId, userInfo);
            return false;
        }

        String lockKey = LOCK_ASR_PREFIX + roomId;
        RLock lock = redissonClient.getLock(lockKey);
        
        boolean isLocked = false;
        try {
            // 尝试获取分布式锁，等待时间3秒，锁有效期10秒
            isLocked = lock.tryLock(3, 10, TimeUnit.SECONDS);
            if (!isLocked) {
                log.warn("获取ASR解析锁失败，直播间ID: {}", roomId);
                return false;
            }

            // 获取当前直播间用户集合
            String usersKey = REDIS_PREFIX_ASR_USERS + roomId;
            Set<String> currentUsers = getAsrUsers(usersKey);
            
            if (currentUsers.isEmpty()) {
                log.warn("ASR解析用户集合为空，直播间ID: {}", roomId);
                return false;
            }

            // 移除当前用户
            boolean userRemoved = currentUsers.remove(userInfo.getUser_id());
            
            // 如果用户集合为空，需要结束ASR解析
            if (currentUsers.isEmpty()) {
                log.info("最后一个用户离开，结束ASR解析，直播间ID: {}, 用户ID: {}", roomId, userInfo.getUser_id());
                
                // 调用业务服务结束ASR解析
                ApiResponse response = businessService.endAsr(roomId);
                if (response != null && response.getCode() == 200) {
                    // 清除用户集合
                    redisTemplate.delete(usersKey);
                    
                    // 清除直播间信息
                    clearAsrInfo(roomId);
                    
                    log.info("ASR解析结束成功，直播间ID: {}, 用户ID: {}", roomId, userInfo.getUser_id());
                    return true;
                } else {
                    log.error("ASR解析结束失败，直播间ID: {}, 响应: {}", roomId, response);
                    // 如果结束失败，恢复用户
                    currentUsers.add(userInfo.getUser_id());
                    saveAsrUsers(usersKey, currentUsers);
                    return false;
                }
            } else {
                // 更新用户集合
                saveAsrUsers(usersKey, currentUsers);
                log.debug("更新ASR解析用户集合，直播间ID: {}, 当前用户数: {}, 移除用户: {}", 
                         roomId, currentUsers.size(), userRemoved);
                return true;
            }

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("结束ASR解析时线程被中断，直播间ID: {}", roomId, e);
            return false;
        } catch (Exception e) {
            log.error("结束ASR解析异常，直播间ID: {}", roomId, e);
            return false;
        } finally {
            if (isLocked && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 检查ASR解析是否已开启
     * 
     * @param roomId 直播间ID
     * @return true表示已开启，false表示未开启
     */
    public boolean isAsrStarted(Integer roomId) {
        if (roomId == null) {
            return false;
        }

        String usersKey = REDIS_PREFIX_ASR_USERS + roomId;
        Set<String> users = getAsrUsers(usersKey);
        return !users.isEmpty();
    }

    /**
     * 获取ASR解析用户数
     * 
     * @param roomId 直播间ID
     * @return 当前用户数
     */
    public Integer getAsrCurrentUserCount(Integer roomId) {
        if (roomId == null) {
            return 0;
        }

        String usersKey = REDIS_PREFIX_ASR_USERS + roomId;
        Set<String> users = getAsrUsers(usersKey);
        return users.size();
    }

    /**
     * 内部方法：获取ASR用户集合
     */
    private Set<String> getAsrUsers(String usersKey) {
        Set<Object> userObjects = redisTemplate.opsForSet().members(usersKey);
        if (userObjects == null) {
            return new HashSet<>();
        }
        
        Set<String> users = new HashSet<>();
        for (Object obj : userObjects) {
            if (obj != null) {
                users.add(obj.toString());
            }
        }
        return users;
    }

    /**
     * 内部方法：保存ASR用户集合
     */
    private void saveAsrUsers(String usersKey, Set<String> users) {
        if (users == null || users.isEmpty()) {
            redisTemplate.delete(usersKey);
        } else {
            redisTemplate.delete(usersKey);
            for (String user : users) {
                redisTemplate.opsForSet().add(usersKey, user);
            }
            redisTemplate.expire(usersKey, CACHE_EXPIRE_HOURS, TimeUnit.HOURS);
        }
    }

    /**
     * 强制结束ASR解析（用于异常情况处理）
     * 
     * @param roomId 直播间ID
     * @return true表示成功，false表示失败
     */
    public boolean forceEndAsr(Integer roomId) {
        if (roomId == null) {
            return false;
        }

        String lockKey = LOCK_ASR_PREFIX + roomId;
        RLock lock = redissonClient.getLock(lockKey);
        
        boolean isLocked = false;
        try {
            isLocked = lock.tryLock(3, 10, TimeUnit.SECONDS);
            if (!isLocked) {
                return false;
            }

            // 强制结束ASR解析
            ApiResponse response = businessService.endAsr(roomId);
            
            // 清除用户集合和直播间信息
            String usersKey = REDIS_PREFIX_ASR_USERS + roomId;
            redisTemplate.delete(usersKey);
            
            clearAsrInfo(roomId);
            
            log.warn("强制结束ASR解析，直播间ID: {}, 响应: {}", roomId, response);
            return response != null && response.getCode() == 200;

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        } catch (Exception e) {
            log.error("强制结束ASR解析异常，直播间ID: {}", roomId, e);
            return false;
        } finally {
            if (isLocked && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 保存直播间信息
     */
    private void saveAsrInfo(Integer roomId, LiveRoom room) {
        if (roomId == null || room == null) {
            return;
        }

        try {
            String infoKey = REDIS_PREFIX_ASR_INFO + roomId;
            // 将直播间信息转换为JSON存储
            String roomJson = JSONUtil.toJsonStr(room);
            redisTemplate.opsForValue().set(infoKey, roomJson, CACHE_EXPIRE_HOURS, TimeUnit.HOURS);
            
            log.debug("保存直播间信息成功，直播间ID: {}", roomId);
        } catch (Exception e) {
            log.error("保存直播间信息异常，直播间ID: {}", roomId, e);
        }
    }

    /**
     * 清除直播间信息
     */
    private void clearAsrInfo(Integer roomId) {
        if (roomId == null) {
            return;
        }

        try {
            String infoKey = REDIS_PREFIX_ASR_INFO + roomId;
            redisTemplate.delete(infoKey);
            
            log.debug("清除直播间信息成功，直播间ID: {}", roomId);
        } catch (Exception e) {
            log.error("清除直播间信息异常，直播间ID: {}", roomId, e);
        }
    }

    /**
     * 获取已开启ASR解析的直播间列表
     */
    public List<Integer> getActiveAsrRooms() {
        try {
            // 通过扫描所有用户集合来获取活跃直播间
            Set<String> keys = redisTemplate.keys(REDIS_PREFIX_ASR_USERS + "*");
            if (keys == null) {
                return new ArrayList<>();
            }
            
            List<Integer> activeRooms = new ArrayList<>();
            for (String key : keys) {
                try {
                    String roomIdStr = key.substring(REDIS_PREFIX_ASR_USERS.length());
                    Integer roomId = Integer.valueOf(roomIdStr);
                    
                    // 检查用户集合是否为空
                    Set<String> users = getAsrUsers(key);
                    if (!users.isEmpty()) {
                        activeRooms.add(roomId);
                    }
                } catch (Exception e) {
                    log.warn("解析直播间ID异常，key: {}", key, e);
                }
            }
            
            return activeRooms;
        } catch (Exception e) {
            log.error("获取已开启ASR解析的直播间列表异常", e);
            return new ArrayList<>();
        }
    }

    /**
     * 获取指定直播间的详细信息
     */
    public LiveRoom getRoomInfo(Integer roomId) {
        if (roomId == null) {
            return null;
        }

        try {
            String infoKey = REDIS_PREFIX_ASR_INFO + roomId;
            Object roomObj = redisTemplate.opsForValue().get(infoKey);
            if (roomObj instanceof String) {
                return JSONUtil.toBean((String) roomObj, LiveRoom.class);
            }
        } catch (Exception e) {
            log.error("获取直播间信息异常，直播间ID: {}", roomId, e);
        }
        
        return null;
    }
}