package com.seer.teach.teacher.service.impl;

import cn.hutool.json.JSONUtil;
import com.seer.teach.common.cache.LlmAudioPublisher;
import com.seer.teach.common.cache.LlmAudioPublisherService;
import com.seer.teach.common.dto.mq.LlmChatDTO;
import com.seer.teach.common.dto.mq.StringDTO;
import com.seer.teach.common.enums.ResultCodeEnum;
import com.seer.teach.common.enums.im.ImMqTopicEnum;
import com.seer.teach.common.enums.im.RedisChannelPushTopTagEnum;
import com.seer.teach.common.enums.im.UserInfoTopiTagEnum;
import com.seer.teach.common.utils.AssertUtils;
import com.seer.teach.teacher.common.dto.ReadingStatusDTO;
import com.seer.teach.teacher.common.utils.TeacherUtils;
import com.seer.teach.teacher.common.utils.UserStatusCacheUtils;
import com.seer.teach.teacher.mq.ImMqProducer;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import jakarta.annotation.PostConstruct;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 读取“阅读结束音频”配置的服务实现类。
 * 在 Spring 容器启动时读取指定 JSON 文件，并将其解析为 List<LlmChatDTO>。
 * 并提供用户推送状态统计
 * </p>
 *
 * <p>
 * 文件路径：resources/config/readEnd.json
 * JSON 内容为音频信息对象列表
 * </p>
 *
 * @author Captain
 * @since 2025-10-16
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ReadEndService {

    private final ImMqProducer imMqProducer;

    /**
     * JSON 配置文件路径（类路径下）
     */
    private static final String FILE_PATH = "config/readEnd.json";

    /**
     * 读取到的结束音频列表
     */
    @Getter
    private List<LlmChatDTO> readEndList = new ArrayList<>();

    private final LlmAudioPublisherService llmAudioPublisherService;

    @PostConstruct
    public void init() {
        loadReadEndList();
    }

    /**
     * 从 JSON 文件读取结束音频列表
     */
    private void loadReadEndList() {
        try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(FILE_PATH)) {
            AssertUtils.notNull(inputStream, ResultCodeEnum.LOCAL_FILE_NOT_FOUND);

            String jsonStr = new String(readInputStreamToByteArray(inputStream), StandardCharsets.UTF_8);
            readEndList = JSONUtil.toList(jsonStr, LlmChatDTO.class);

            log.info("成功加载阅读结束音频配置，数量={}", readEndList.size());
        } catch (IOException e) {
            throw new RuntimeException("读取阅读结束音频配置文件失败：" + FILE_PATH, e);
        }
    }

    /**
     * 将 InputStream 读取为字节数组
     */
    private byte[] readInputStreamToByteArray(InputStream inputStream) throws IOException {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            byte[] buffer = new byte[1024];
            int len;
            while ((len = inputStream.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }
            return baos.toByteArray();
        }
    }

    /**
     * 推送阅读结束音频给指定用户
     *
     * @param userId 用户 ID
     * @param device 设备标识
     */
    public void pushReadEnd(Integer userId, String device) {
        try {

            Integer sessionId = TeacherUtils.generateSessionId(userId, device);
            // 通过Redis发送消息到IM消息队列，推送LLM音频数据到指定设备
            String channelName = sendChannelName(device, sessionId);
            updatePushTime(device, channelName);
            Thread.sleep(2000);
            readEndList.stream().forEach(data -> {
                data.setId(sessionId);
                data.setMqTime(System.currentTimeMillis());
                llmAudioPublisherService.publishToDevice(device + sessionId, data);
            });
            ReadingStatusDTO reading = UserStatusCacheUtils.getReading(userId);
            // 循环完成后，记录用户推送完成状态 为后续触发 继续阅读状态做指令
            reading.setIsEnd(true);
            UserStatusCacheUtils.setReading(userId, reading);
            log.info("用户 {} 阅读结束音频推送完成", userId);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 发送频道名称到指定设备
     *
     * @param device 设备标识
     */
    private String sendChannelName(String device, Integer sessionId) {
        imMqProducer.sendMsgWithReplyViaRedis(
                ImMqTopicEnum.REDIS_CHANNEL_PUSH,
                RedisChannelPushTopTagEnum.PUSH_LLM_AUDIO.getTag(),
                device,
                JSONUtil.toJsonStr(new StringDTO(device + sessionId)),
                3
        );
        return LlmAudioPublisher.getChannel(device + sessionId);
    }

    /**
     * 更新推送时间
     *
     * @param device 设备标识
     */
    private void updatePushTime(String device, String channelName) {
        // 异步发送更新推送时间的消息
        imMqProducer.sendMsgAsync(
                ImMqTopicEnum.USER_INFO,
                UserInfoTopiTagEnum.UPDATE_PUSH_TIME.getTag(),
                device,
                JSONUtil.toJsonStr(new StringDTO(channelName))
        );
    }


    /**
     * 查询用户是否已经推送完成，并在查询后清除记录
     *
     * @param userId 用户 ID
     * @return true 表示已推送完成，false 表示未推送或已清除
     */
    public boolean hasPushedAndClear(Integer userId) {
        ReadingStatusDTO readingStatus = UserStatusCacheUtils.getReading(userId);
        if (readingStatus != null && readingStatus.getIsEnd()) {
            return true;
        }
        return false;
    }
}
