package com.cmvr.llm.service.impl;

import cn.hutool.core.io.resource.Resource;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.cmvr.common.exception.GlobalException;
import com.cmvr.common.utils.http.CallAPIUtil;
import com.cmvr.common.utils.uuid.IdUtils;
import com.cmvr.llm.config.APIProperties;
import com.cmvr.llm.model.CallAgentAdvancedVO;
import com.cmvr.llm.model.CallAgentVO;
import com.cmvr.llm.model.CallTTSAdvancedVO;
import com.cmvr.llm.model.CallTTSVO;
import com.cmvr.llm.service.LargeModelRemoteService;
import com.cmvr.llm.service.ShowIntelligentCockpitService;
import com.cmvr.llm.util.LargeModelFileUploadUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.UriUtils;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class ShowIntelligentCockpitServiceImpl implements ShowIntelligentCockpitService {

    private final APIProperties apiProperties;
    private final LargeModelRemoteService largeModelRemoteService;
    private final RedisTemplate<String, String> redisTemplate;
    private static final String TIMBRE_CONFIG_KEY = "show:tts:timbre";

    /**
     * 创建音色
     */
    @Override
    public String createTimbre(MultipartFile file) {
        String originalFilename = file.getOriginalFilename();
        if (!StrUtil.endWith(originalFilename, ".wav") && !StrUtil.endWith(originalFilename, ".m4a")) {
            throw new GlobalException("音频文件的类型必须为 .wav 或者 .m4a");
        }
        // 上传文件
        String url = "http://10.148.108.16:8000/upload_file";
        HttpResponse response = HttpRequest.post(url)
                .form("file", new Resource() {
                    @Override
                    public String getName() {
                        return file.getOriginalFilename();
                    }

                    @Override
                    public URL getUrl() {
                        return null;
                    }

                    @Override
                    public InputStream getStream() {
                        try {
                            return file.getInputStream();
                        } catch (IOException e) {
                            throw new GlobalException(e.getMessage());
                        }
                    }
                })
                .timeout(5000)
                .execute();
        String body = response.body();
        JSONObject object = JSON.parseObject(body);
        String filename = object.getString("filename");
        if (StrUtil.isEmpty(filename)) {
            throw new GlobalException("文件上传失败，未获取到文件名！");
        }
        // 保存音色
        redisTemplate.opsForHash().put(TIMBRE_CONFIG_KEY, IdUtils.fastSimpleUUID(), StrUtil.subBefore(filename, StrUtil.DOT, false));

        return filename;
    }

    /**
     * 查询音色和方言
     */
    @Override
    public List<String> queryTimbre() {
        return redisTemplate.opsForHash().entries(TIMBRE_CONFIG_KEY)
                .values()
                .stream()
                .filter(value -> value instanceof String)
                .map(Object::toString)
                .collect(Collectors.toList());
    }

    /**
     * 生成语料
     */
    @Override
    public String genCorpus(CallAgentVO callAgentVO) {
        return largeModelRemoteService.runSpeechToTextWorkflow(callAgentVO);
    }

    /**
     * 语音合成
     */
    @Override
    public ResponseEntity<byte[]> synthesizeAudio(CallTTSVO callTTSVO) {
        // 1. 构建请求体
        Map<String, Object> body = new HashMap<>();
        body.put("text", callTTSVO.getText());
        body.put("dialect", callTTSVO.getDialect());
        body.put("timbre", callTTSVO.getTimbre());

        // 2. 发送请求到语音合成服务
        HttpResponse response = HttpRequest.post("http://10.148.108.16:8000/generate_audio")
                .header("Content-Type", "application/json")
                .body(JSON.toJSONString(body))
                .execute();

        if (!response.isOk()) {
            throw new GlobalException("音频生成失败，状态码: " + response.getStatus());
        }

        // 3. 获取音频数据
        byte[] audioData = response.bodyBytes();

        // 4. 设置响应头：audio/wav + inline 播放 + 文件名
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.parseMediaType("audio/wav"));
        headers.setContentLength(audioData.length);

        // 生成文件名并编码（避免中文乱码）
        String rawFilename = callTTSVO.getTimbre() + "_" + callTTSVO.getText() + ".wav";
        String encodedFilename = UriUtils.encode(rawFilename, StandardCharsets.UTF_8);

        headers.set(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + encodedFilename + "\"");

        return new ResponseEntity<>(audioData, headers, HttpStatus.OK);
    }

    /**
     * 生成语料-增强
     */
    @Override
    public String genCorpusAdvanced(CallAgentAdvancedVO callAgentAdvancedVO) {
        Map<String, String> headers = new HashMap<>();
        headers.put("Apikey", "d0ncehbnjkfk0lg0bnlg");

        Map<String, String> body = new HashMap<>();
        body.put("AppKey", "d0ncehbnjkfk0lg0bnlg");
        body.put("AppID", "d0nce8bnjkfk0lg0bg60");
        body.put("InputData", JSON.toJSONString(callAgentAdvancedVO));
        body.put("UserID", "18888888888");

        String res = CallAPIUtil.doPostJson(apiProperties.getWorkFlowUrl(), headers, body);
        JSONObject resObject = JSON.parseObject(res);

        if (resObject.containsKey("runId")) {
            String processId = resObject.getString("runId");
            return querySpeechToTextResult(processId);
        } else {
            throw new RuntimeException("未获取到 runId，响应内容：" + res);
        }
    }

    /**
     * 语音合成-增强
     */
    @Override
    public ResponseEntity<byte[]> synthesizeAudioAdvanced(CallTTSAdvancedVO callTTSAdvancedVO) {
        // 1. 构建请求体
        Map<String, Object> body = new HashMap<>();
        body.put("text", callTTSAdvancedVO.getText());
        body.put("dialect", callTTSAdvancedVO.getDialect());
        body.put("timbre", callTTSAdvancedVO.getTimbre());
        body.put("language", callTTSAdvancedVO.getLanguage());
        body.put("tone", callTTSAdvancedVO.getTone());

        // 2. 发送请求到语音合成服务
        HttpResponse response = HttpRequest.post("http://10.148.108.16:8000/generate_advanced_audio")
                .header("Content-Type", "application/json")
                .body(JSON.toJSONString(body))
                .execute();

        if (!response.isOk()) {
            throw new GlobalException("音频生成失败，状态码: " + response.getStatus());
        }

        // 3. 获取音频数据
        byte[] audioData = response.bodyBytes();

        // 4. 设置响应头：audio/wav + inline 播放 + 文件名
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.parseMediaType("audio/wav"));
        headers.setContentLength(audioData.length);

        // 生成文件名并编码（避免中文乱码）
        String rawFilename = callTTSAdvancedVO.getTimbre() + "_" + callTTSAdvancedVO.getText() + ".wav";
        String encodedFilename = UriUtils.encode(rawFilename, StandardCharsets.UTF_8);

        headers.set(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + encodedFilename + "\"");

        return new ResponseEntity<>(audioData, headers, HttpStatus.OK);
    }

    /**
     * 获取触控坐标
     */
    @Override
    public String getCoordinates(byte[] bytes, String words) throws Exception {
        // 先上传图片获取url
        String url = LargeModelFileUploadUtil.uploadFile(bytes);
        if (StrUtil.isEmpty(url)) {
            throw new GlobalException("获取图片url失败！");
        }

        // 调用触控交互接口
        Map<String, String> params = new HashMap<>();
        String str =
                StrUtil.isEmpty(words) ?
                        "我需要打开应用中心，请给出打开应用中心需要触控的文本或图标，仅输出标定框，输出格式为[x1,y1,x2,y2]，其中x1，y1为标定框左上角的坐标，x2，y2为标定框右下角的坐标" : words;
        params.put("user_data", str);
        params.put("user_image", url);

        Map<String, String> headers = new HashMap<>();
        headers.put("Apikey", "d0jas9jnjkfk0lm3bl9g");

        Map<String, String> body = new HashMap<>();
        body.put("AppKey", "d0jas9jnjkfk0lm3bl9g");
        body.put("AppID", "d0ja89bnjkfk0lm31tcg");
        body.put("InputData", JSON.toJSONString(params));
        body.put("UserID", "18888888888");

        String res1 = CallAPIUtil.doPostJson(apiProperties.getWorkFlowUrl(), headers, body);
        JSONObject resObject1 = JSON.parseObject(res1);
        if (resObject1.containsKey("runId")) {
            String processId = resObject1.getString("runId");
            return queryResultByRunId(processId);
        } else {
            throw new GlobalException("未获取到 runId，响应内容：" + res1);
        }
    }

    private String queryResultByRunId(String processId) {
        Map<String, String> headers = new HashMap<>();
        headers.put("Apikey", "d0jas9jnjkfk0lm3bl9g");

        Map<String, String> body = new HashMap<>();
        body.put("AppKey", "d0jas9jnjkfk0lm3bl9g");
        body.put("AppID", "d0ja89bnjkfk0lm31tcg");
        body.put("RunID", processId);
        body.put("UserID", "18888888888");

        String responseBody;
        JSONObject endNode;
        int failCount = 0;
        int maxFail = 40;

        while (true) {
            responseBody = CallAPIUtil.doPostJson(apiProperties.getQueryResultUrl(), headers, body);
            JSONObject jsonObject = JSON.parseObject(responseBody);

            String status = jsonObject.getString("status");
            if ("success".equals(status)) {
                JSONObject nodes = jsonObject.getJSONObject("nodes");
                if (nodes == null) {
                    throw new GlobalException("响应中 nodes 为空：" + responseBody);
                }

                endNode = findEndNode(nodes);
                if (endNode != null) {
                    break;
                } else {
                    throw new GlobalException("未找到 nodeType=end 的节点：" + nodes);
                }
            } else if ("failed".equals(status)) {
                // 如果失败
                throw new GlobalException(responseBody);
            } else {
                // 处理其他状态码
                failCount++;
                if (failCount > maxFail) {
                    throw new GlobalException("达到最大重试次数，API状态仍未成功：" + status);
                }
            }

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new GlobalException("轮询被中断");
            }
        }

        // 解析 output 内容并清洗
        JSONObject output = endNode.getJSONObject("output");
        String res = output.getString("content");
        if (StrUtil.isEmpty(res)) {
            throw new GlobalException("未找到坐标内容");
        }
        return res;
    }

    /**
     * 从 nodes 中提取 nodeType=end 的节点
     */
    private JSONObject findEndNode(JSONObject nodes) {
        for (Map.Entry<String, Object> entry : nodes.entrySet()) {
            JSONObject node = (JSONObject) entry.getValue();
            if ("end".equalsIgnoreCase(node.getString("nodeType"))) {
                return node;
            }
        }
        return null;
    }

    public String querySpeechToTextResult(String processId) {
        Map<String, String> headers = new HashMap<>();
        headers.put("Apikey", "d0ncehbnjkfk0lg0bnlg");

        Map<String, String> body = new HashMap<>();
        body.put("AppKey", "d0ncehbnjkfk0lg0bnlg");
        body.put("AppID", "d0nce8bnjkfk0lg0bg60");
        body.put("RunID", processId);
        body.put("UserID", "18888888888");

        String responseBody;
        JSONObject endNode;
        int failCount = 0;
        int maxFail = 40;

        while (true) {
            responseBody = CallAPIUtil.doPostJson(apiProperties.getQueryResultUrl(), headers, body);
            JSONObject jsonObject = JSON.parseObject(responseBody);

            String status = jsonObject.getString("status");
            if ("success".equals(status)) {
                JSONObject nodes = jsonObject.getJSONObject("nodes");
                if (nodes == null) {
                    throw new RuntimeException("响应中 nodes 为空：" + responseBody);
                }

                endNode = findEndNode(nodes);
                if (endNode != null) {
                    break;
                } else {
                    throw new RuntimeException("未找到 nodeType=end 的节点：" + nodes);
                }
            }else if ("failed".equals(status)) {
                // 如果失败
                throw new GlobalException(responseBody);
            } else {
                // 处理其他状态码
                failCount++;
                if (failCount > maxFail) {
                    throw new GlobalException("达到最大重试次数，API状态仍未成功：" + status);
                }
            }

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("轮询被中断", e);
            }
        }

        // 解析 output 内容并清洗
        JSONObject output = JSON.parseObject(endNode.getString("output"));
        return output.getString("content");
    }
}
