package org.dromara.talk.service.impl;

import com.alibaba.fastjson2.JSON;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.talk.config.XunfeiConfig;
import org.dromara.talk.domain.vo.TalkAgentVo;
import org.dromara.talk.service.ITtsService;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.stereotype.Service;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
@Service
@AllArgsConstructor
public class TtsServiceImpl implements ITtsService {

    private final XunfeiConfig xunfeiConfig;

    private static final String HOST_URL = "https://tts-api.xfyun.cn/v2/tts";

    @Override
    public void synthesize(String text, TalkAgentVo agentConfig, ITtsService.AudioCallback callback) {
        try {
            String wsUrl = getAuthUrl(HOST_URL, xunfeiConfig.getApiKey(), xunfeiConfig.getApiSecret()).replace("https://", "wss://");
            URI uri = new URI(wsUrl);
            String requestJson = buildRequest(text, agentConfig);

            WebSocketClient client = new WebSocketClient(uri) {
                @Override
                public void onOpen(ServerHandshake handshake) {
                    log.info("TTS WebSocket连接成功");
                    send(requestJson);
                }

                @Override
                public void onMessage(String message) {
                    log.info("收到TTS响应: {}", message);
                    TtsResponse response = JSON.parseObject(message, TtsResponse.class);

                    if (response.code != 0) {
                        log.error("TTS返回错误: code={}, message={}", response.code, response.message);
                        callback.onError(response.code, response.message);
                        return;
                    }

                    if (response.data != null && response.data.audio != null) {
                        callback.onAudio(response.data.audio, response.data.status);
                    }
                }

                @Override
                public void onClose(int code, String reason, boolean remote) {
                    log.info("TTS WebSocket连接关闭: code={}, reason={}, remote={}", code, reason, remote);
                }

                @Override
                public void onError(Exception e) {
                    log.error("TTS WebSocket错误", e);
                    callback.onError(-1, e.getMessage());
                }
            };

            client.connect();

        } catch (Exception e) {
            log.error("TTS合成失败", e);
            callback.onError(-1, e.getMessage());
        }
    }

    @Override
    public void synthesizeStream(String text, TalkAgentVo agentConfig, java.util.function.BiConsumer<String, Integer> callback) {
        try {
            String wsUrl = getAuthUrl(HOST_URL, xunfeiConfig.getApiKey(), xunfeiConfig.getApiSecret()).replace("https://", "wss://");
            URI uri = new URI(wsUrl);
            String requestJson = buildRequest(text, agentConfig);

            WebSocketClient client = new WebSocketClient(uri) {
                @Override
                public void onOpen(ServerHandshake handshake) {
                    log.info("TTS WebSocket连接成功(流式)");
                    send(requestJson);
                }

                @Override
                public void onMessage(String message) {
                    log.info("TTS流式收到响应: {}", message.length() > 200 ? message.substring(0, 200) + "..." : message);
                    TtsResponse response = JSON.parseObject(message, TtsResponse.class);

                    if (response.code != 0) {
                        log.error("TTS返回错误: code={}, message={}", response.code, response.message);
                        return;
                    }

                    if (response.data != null && response.data.audio != null) {
                        log.info("TTS流式收到音频数据: status={}, 音频长度={}", response.data.status, response.data.audio.length());
                        callback.accept(response.data.audio, response.data.status);
                    } else {
                        log.warn("TTS流式响应中没有音频数据: data={}", response.data);
                    }
                }

                @Override
                public void onClose(int code, String reason, boolean remote) {
                    log.info("TTS WebSocket连接关闭(流式)");
                }

                @Override
                public void onError(Exception e) {
                    log.error("TTS WebSocket错误(流式)", e);
                }
            };

            client.connect();

        } catch (Exception e) {
            log.error("TTS流式合成失败", e);
        }
    }

    private String buildRequest(String text, TalkAgentVo agentConfig) {
        // 使用客服配置的TTS参数，如果没有则使用默认值
        String vcn = agentConfig != null && agentConfig.getTtsVcn() != null ? agentConfig.getTtsVcn() : "x4_yezi";
        Long speed = agentConfig != null && agentConfig.getTtsSpeed() != null ? agentConfig.getTtsSpeed() : 50L;
        Long pitch = agentConfig != null && agentConfig.getTtsPitch() != null ? agentConfig.getTtsPitch() : 50L;
        Long volume = agentConfig != null && agentConfig.getTtsVolume() != null ? agentConfig.getTtsVolume() : 50L;
        Long bgs = agentConfig != null && agentConfig.getTtsBgs() != null ? agentConfig.getTtsBgs() : 0L;

        return "{\n" +
                "  \"common\": {\"app_id\": \"" + xunfeiConfig.getAppId() + "\"},\n" +
                "  \"business\": {\n" +
                "    \"aue\": \"lame\",\n" +
                "    \"tte\": \"UTF8\",\n" +
                "    \"ent\": \"intp65\",\n" +
                "    \"vcn\": \"" + vcn + "\",\n" +
                "    \"speed\": " + speed + ",\n" +
                "    \"pitch\": " + pitch + ",\n" +
                "    \"volume\": " + volume + ",\n" +
                "    \"bgs\": " + bgs + "\n" +
                "  },\n" +
                "  \"data\": {\n" +
                "    \"status\": 2,\n" +
                "    \"text\": \"" + Base64.getEncoder()
                .encodeToString(text.getBytes(StandardCharsets.UTF_8)) + "\"\n" +
                "  }\n" +
                "}";
    }

    private String getAuthUrl(String hostUrl, String apiKey, String apiSecret) throws Exception {
        URL url = new URL(hostUrl);
        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = format.format(new Date());

        String preStr = "host: " + url.getHost() + "\n" +
                "date: " + date + "\n" +
                "GET " + url.getPath() + " HTTP/1.1";

        Mac mac = Mac.getInstance("hmacsha256");
        SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "hmacsha256");
        mac.init(spec);
        byte[] hexDigits = mac.doFinal(preStr.getBytes(StandardCharsets.UTF_8));
        String sha = Base64.getEncoder().encodeToString(hexDigits);

        String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"",
                apiKey, "hmac-sha256", "host date request-line", sha);

        String authBase64 = Base64.getEncoder().encodeToString(authorization.getBytes(StandardCharsets.UTF_8));

        return "https://" + url.getHost() + url.getPath() +
               "?authorization=" + authBase64 +
               "&date=" + URLEncoder.encode(date, StandardCharsets.UTF_8) +
               "&host=" + url.getHost();
    }

    static class TtsResponse {
        public int code;
        public String message;
        public String sid;
        public TtsData data;
    }

    static class TtsData {
        public int status;
        public String audio;
        public String ced;
    }
}
