package cn.iocoder.byzs.module.ai.controller.admin.speech;

import cn.iocoder.byzs.framework.common.pojo.CommonResult;
import com.alibaba.nls.client.AccessToken;
import com.alibaba.nls.client.protocol.InputFormatEnum;
import com.alibaba.nls.client.protocol.NlsClient;
import com.alibaba.nls.client.protocol.SampleRateEnum;
import com.alibaba.nls.client.protocol.asr.SpeechTranscriber;
import com.alibaba.nls.client.protocol.asr.SpeechTranscriberListener;
import com.alibaba.nls.client.protocol.asr.SpeechTranscriberResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.web.bind.annotation.*;

import java.util.concurrent.ConcurrentHashMap;

import static cn.iocoder.byzs.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
import static cn.iocoder.byzs.framework.common.pojo.CommonResult.success;

@Tag(name = "管理后台 - AI 语音识别")
@RestController
@RequestMapping("/admin/speech/recognition")
@Slf4j
public class SpeechRecognitionController {

    // 存储每个会话的识别器
    private final ConcurrentHashMap<String, SpeechTranscriber> transcriberMap = new ConcurrentHashMap<>();
    // 存储每个会话的NlsClient
    private final ConcurrentHashMap<String, NlsClient> clientMap = new ConcurrentHashMap<>();
    // 存储每个会话的识别结果
    private final ConcurrentHashMap<String, String> resultMap = new ConcurrentHashMap<>();
    // 存储累积识别结果的映射，键为sessionId，值为累积的识别结果
    private final ConcurrentHashMap<String, String> accumulatedResultMap = new ConcurrentHashMap<>();

    // 配置参数
    private final String appKey = "4SUOF4LfaU7FekyW";
    private final String accessKeyId = "LTAI5tQhMPLXtSgXiPiWbw6D";
    private final String accessKeySecret = "HCXpFYjl4swk0qwfIKa9s2bXx0AWcG";
    private final String url = System.getenv().getOrDefault("NLS_GATEWAY_URL", "wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1");

    public SpeechRecognitionController(GroupedOpenApi systemGroupedOpenApi) {
    }

    @PostMapping("/start")
    @Operation(summary = "开始语音识别")
    @Parameter(name = "sessionId", description = "会话ID", required = true)
    public CommonResult<String> startRecognition(@RequestParam("sessionId") String sessionId) {
        try {
            // 获取token
            AccessToken accessToken = new AccessToken(accessKeyId, accessKeySecret);
            accessToken.apply();
            log.info("get token: {}, expire time: {}", accessToken.getToken(), accessToken.getExpireTime());

            // 创建NlsClient
            NlsClient client = new NlsClient(url, accessToken.getToken());
            clientMap.put(sessionId, client);

            // 创建SpeechTranscriber
            SpeechTranscriber transcriber = new SpeechTranscriber(client, getTranscriberListener(sessionId));
            transcriber.setAppKey(appKey);
            transcriber.setFormat(InputFormatEnum.PCM);
            transcriber.setSampleRate(SampleRateEnum.SAMPLE_RATE_16K);
            transcriber.setEnableIntermediateResult(true);
            transcriber.setEnablePunctuation(true);
            transcriber.setEnableITN(false);

            // 开始识别
            transcriber.start();
            transcriberMap.put(sessionId, transcriber);

            return success("Recognition started");
        } catch (Exception e) {
            log.error("Error starting recognition", e);
            return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), "Failed to start recognition");
        }
    }

    @PostMapping("/send")
    @Operation(summary = "发送音频数据")
    @Parameter(name = "sessionId", description = "会话ID", required = true)
    public CommonResult<String> sendAudio(@RequestParam("sessionId") String sessionId, @RequestBody byte[] audioData) {
        try {
            SpeechTranscriber transcriber = transcriberMap.get(sessionId);
            if (transcriber == null) {
                return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), "Recognition not started");
            }

            // 发送音频数据
            // 注意：这里直接发送前端传来的音频数据
            // 实际项目中可能需要根据前端发送的音频格式进行适当处理
            transcriber.send(audioData, audioData.length);
            return success("Audio data received");
        } catch (Exception e) {
            log.error("Error sending audio data", e);
            return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), "Failed to send audio data");
        }
    }

    @PostMapping("/stop")
    @Operation(summary = "停止语音识别")
    @Parameter(name = "sessionId", description = "会话ID", required = true)
    public CommonResult<String> stopRecognition(@RequestParam("sessionId") String sessionId) {
        try {
            SpeechTranscriber transcriber = transcriberMap.remove(sessionId);
            NlsClient client = clientMap.remove(sessionId);

            if (transcriber != null) {
                transcriber.stop();
                transcriber.close();
            }

            if (client != null) {
                client.shutdown();
            }

            // 保留识别结果，以便前端获取

            return success("Recognition stopped");
        } catch (Exception e) {
            log.error("Error stopping recognition", e);
            return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), "Failed to stop recognition");
        }
    }

    @GetMapping("/result")
    @Operation(summary = "获取识别结果")
    @Parameter(name = "sessionId", description = "会话ID", required = true)
    public CommonResult<RecognitionResult> getRecognitionResult(@RequestParam("sessionId") String sessionId) {
        try {
            // 先获取累积的识别结果
            String accumulatedResult = accumulatedResultMap.get(sessionId);
            if (accumulatedResult == null) {
                accumulatedResult = "";
            }
            // 获取最新的中间结果
            String latestResult = resultMap.get(sessionId);
            if (latestResult == null) {
                latestResult = "";
            }
            // 如果累积结果为空，使用最新结果；否则确保最新结果已包含在累积结果中
            String finalResult = accumulatedResult.isEmpty() ? latestResult : accumulatedResult;
            System.out.println("【获取识别结果】 " + sessionId + "-----" + finalResult);
            return success(new RecognitionResult(finalResult));
        } catch (Exception e) {
            log.error("Error getting recognition result", e);
            return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), "Failed to get recognition result");
        }
    }

    // 识别结果封装类
    private static class RecognitionResult {
        private String result;

        public RecognitionResult(String result) {
            this.result = result;
        }

        public String getResult() {
            return result;
        }

        public void setResult(String result) {
            this.result = result;
        }
    }

    private SpeechTranscriberListener getTranscriberListener(String sessionId) {
        return new SpeechTranscriberListener() {
            @Override
            public void onTranscriptionResultChange(SpeechTranscriberResponse response) {
                String result = response.getTransSentenceText();
                log.info("Session {} - Intermediate result: {}", sessionId, result);
                // 更新最新结果
                resultMap.put(sessionId, result);
            }

            @Override
            public void onTranscriberStart(SpeechTranscriberResponse response) {
                log.info("Session {} - Recognition started: {}", sessionId, response.getTaskId());
                // 初始化识别结果
                resultMap.put(sessionId, "");
                accumulatedResultMap.put(sessionId, "");
            }

            @Override
            public void onSentenceBegin(SpeechTranscriberResponse response) {
                log.info("Session {} - Sentence begun", sessionId);
            }

            @Override
            public void onSentenceEnd(SpeechTranscriberResponse response) {
                String result = response.getTransSentenceText();
                log.info("Session {} - Sentence ended: {}", sessionId, result);
                // 保持最终结果
                resultMap.put(sessionId, result);
                // 将新句子追加到累积结果中，保留历史句子
                String oldResult = accumulatedResultMap.get(sessionId);
                if (oldResult == null) {
                    oldResult = "";
                }
                accumulatedResultMap.put(sessionId, oldResult + result);
            }

            @Override
            public void onTranscriptionComplete(SpeechTranscriberResponse response) {
                log.info("Session {} - Recognition completed", sessionId);
            }

            @Override
            public void onFail(SpeechTranscriberResponse response) {
                String errorMessage = response.getStatusText();
                log.error("Session {} - Recognition failed: {} - {}", sessionId, response.getStatus(), errorMessage);
                // 更新错误信息
                resultMap.put(sessionId, "Error: " + errorMessage);
            }
        };
    }

    // 计算睡眠时长，用于模拟实时流
    private int getSleepDelta(int dataSize, int sampleRate) {
        int sampleBytes = 16;
        int soundChannel = 1;
        return (dataSize * 10 * 8000) / (160 * sampleRate);
    }
}