package org.dromara.talk.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.dromara.talk.service.ITtsService;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.beans.factory.annotation.Value;
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
public class TtsServiceImpl implements ITtsService {

    @Value("${xfyun.tts.appid:}")
    private String appId;

    @Value("${xfyun.tts.api-key:}")
    private String apiKey;

    @Value("${xfyun.tts.api-secret:}")
    private String apiSecret;

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

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

            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());
        }
    }

    private String buildRequest(String text) {
        return "{\n" +
                "  \"common\": {\"app_id\": \"" + appId + "\"},\n" +
                "  \"business\": {\n" +
                "    \"aue\": \"lame\",\n" +
                "    \"tte\": \"UTF8\",\n" +
                "    \"ent\": \"intp65\",\n" +
                "    \"vcn\": \"x4_yezi\",\n" +
                "    \"speed\": 50,\n" +
                "    \"pitch\": 50\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;
    }
}
