package com.xueyi.nlt.netty.client;

import com.alibaba.fastjson2.JSONObject;
import com.alibaba.nacos.shaded.com.google.gson.Gson;
import com.alibaba.nacos.shaded.com.google.gson.JsonArray;
import com.alibaba.nacos.shaded.com.google.gson.JsonObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.xueyi.nlt.api.netty.domain.vo.DmWebSocketMessageVo;
import com.xueyi.nlt.nlt.domain.vo.LlmQueryVo;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.Serializable;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.*;

@Component
public class WebSocketClient extends WebSocketListener {

    public static WebSocketClient INSTANCE;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    @Value("${secret.spark.appId}")
    private String appId;

    @Value("${secret.spark.apiSecret}")
    private String apiSecret;

    @Value("${secret.spark.apiKey}")
    private String apiKey;

    public final static Object LOCK = new Object();
    public static String hostUrl = "https://spark-api.xf-yun.com/v2.1/chat";
//    public static String APPID = "3d9282da";//从开放平台控制台中获取
//    public static String APIKEY = "7c217b3a313f4b66fcc14a8e97f85103";//从开放平台控制台中获取
//    public static String APISecret = "ZTRiNDQwMTRlOTlmZDQwMDUwYTdjMDM0";//从开放平台控制台中获取

    public static WebSocket webSocket;
    public static String APPID = "948cf4b6";//从开放平台控制台中获取
    public static String APIKEY = "54f6e81f40a31d66d976496de895a7a4";//从开放平台控制台中获取
    public static String APISecret = "ZDYyMjNmMTlkYTE0YWRmOWUwZTYxNjYz";//从开放平台控制台中获取
    public static final Gson json = new Gson();
//    public static String question = "假设你是一位前台，你需要通过与其他人对话来获取会议相关信息，已知今天是2023-7-19，你需要获取会议日期，开始时间，持续时间，会议地点，会议主题。时间用类似00:00的格式输出。对方的话中可能不包含全部信息，对于未知的信息填充为none。如果所有信息都已知那么commit为true。否则为false。将你获得的信息输出为json格式。对方的话是：“明天下午开个会。从两点开到下午三点，在大会议室开，主题是访客接待”，只输出最后的json。输出只有一行，输出格式为{date：，start_time：，duration：，location：，theme：commit：}。";//可以修改question 内容，来向模型提问
    public static String question = "请帮我安排五一出行计划";//可以修改question 内容，来向模型提问
    public static List<String> questions = new ArrayList<>();//可以修改question 内容，来向模型提问
    public String answer = "";

    @PostConstruct
    public void init() {
        INSTANCE = this;
        INSTANCE.redisTemplate = this.redisTemplate;
        INSTANCE.stringRedisTemplate = this.stringRedisTemplate;
        INSTANCE.appId = this.appId;
    }

    public static void main(String[] args) {
        synchronized (LOCK) {
            try {
                //构建鉴权httpurl
                String authUrl = getAuthorizationUrl(hostUrl, INSTANCE.apiKey, INSTANCE.apiSecret);
                OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
                String url = authUrl.replace("https://","wss://").replace("http://","ws://");
                Request request = new Request.Builder().url(url).build();
                WebSocket webSocket = okHttpClient.newWebSocket(request,new WebSocketClient());
                LOCK.wait();
                System.out.println("查询完成");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }



        // write your code here

    }

    /**
     * 调用讯飞开放平台接口发送消息，并将消息存入redis队列
     * @param message
     * @param key
     */
    public void sendMsg(String message,String key){
        LlmQueryVo vo = new LlmQueryVo();
        vo.setQuestion(message);
        vo.setTemplate(key);
        redisTemplate.opsForList().rightPush("group:websocket:quary",vo);
        sendMsg(message);
    }
    public void sendMsg(String message){
        question = message;

        try {
            //构建鉴权httpurl
            String authUrl = getAuthorizationUrl(hostUrl,apiKey,apiSecret);
            OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
            String url = authUrl.replace("https://","wss://").replace("http://","ws://");
            Request request = new Request.Builder().url(url).build();
            webSocket = okHttpClient.newWebSocket(request,new WebSocketClient());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void sendMsg(List<String> messages){
        questions = messages;
        question = null;

        try {
            //构建鉴权httpurl
            String authUrl = getAuthorizationUrl(hostUrl,apiKey,apiSecret);
            OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
            String url = authUrl.replace("https://","wss://").replace("http://","ws://");
            Request request = new Request.Builder().url(url).build();
            webSocket = okHttpClient.newWebSocket(request,new WebSocketClient());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //鉴权url
    public static String  getAuthorizationUrl(String hostUrl , String apikey ,String apisecret) throws Exception {
        //获取host
        URL url = new URL(hostUrl);
        //获取鉴权时间 date
        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        System.out.println("format:\n" + format );
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = format.format(new Date());
        //获取signature_origin字段
        StringBuilder builder = new StringBuilder("host: ").append(url.getHost()).append("\n").
                append("date: ").append(date).append("\n").
                append("GET ").append(url.getPath()).append(" HTTP/1.1");
        System.out.println("signature_origin:\n" + builder);
        //获得signatue
        Charset charset = Charset.forName("UTF-8");
        Mac mac = Mac.getInstance("hmacsha256");
        SecretKeySpec sp = new SecretKeySpec(apisecret.getBytes(charset),"hmacsha256");
        mac.init(sp);
        byte[] basebefore = mac.doFinal(builder.toString().getBytes(charset));
        String signature = Base64.getEncoder().encodeToString(basebefore);
        //获得 authorization_origin
        String authorization_origin = String.format("api_key=\"%s\",algorithm=\"%s\",headers=\"%s\",signature=\"%s\"",apikey,"hmac-sha256","host date request-line",signature);
        //获得authorization
        String authorization = Base64.getEncoder().encodeToString(authorization_origin.getBytes(charset));
        //获取httpurl
        HttpUrl httpUrl = HttpUrl.parse("https://" + url.getHost() + url.getPath()).newBuilder().//
                addQueryParameter("authorization", authorization).//
                addQueryParameter("date", date).//
                addQueryParameter("host", url.getHost()).//
                build();

        return httpUrl.toString();
    }

    //重写onopen
    @Override
    public void onOpen(WebSocket webSocket, Response response) {
        super.onOpen(webSocket, response);
        new Thread(()->{
            JsonObject frame = new JsonObject();
            JsonObject header = new JsonObject();
            JsonObject chat = new JsonObject();
            JsonObject parameter = new JsonObject();
            JsonObject payload = new JsonObject();
            JsonObject message = new JsonObject();
            JsonObject text = new JsonObject();
            JsonArray ja = new JsonArray();

            //填充header
            header.addProperty("app_id",INSTANCE.appId);
            header.addProperty("uid","123456789");
            //填充parameter
//            chat.addProperty("domain","general");     //1.0版本
            chat.addProperty("domain","generalv2");   // 2.0版本
            chat.addProperty("random_threshold",0.5);
            chat.addProperty("max_tokens",1024);
            chat.addProperty("auditing","default");
            parameter.add("chat",chat);
            if (!StringUtils.isEmpty(question)) {
                text = new JsonObject();
                //填充payload
                text.addProperty("role","user");
                text.addProperty("content",question);
                ja.add(text);
            }else {
                for (int i = 0;i < questions.size();i++) {

                    text = new JsonObject();
                    if (i % 2 == 0) {
                        text.addProperty("role","user");

                    } else {
                        text.addProperty("role","assistant");
                    }
                    text.addProperty("content",questions.get(i));
                    System.out.println(text.toString());
                    ja.add(text);
                }
            }
//            message.addProperty("text",ja.getAsString());
            message.add("text",ja);
            payload.add("message",message);
            frame.add("header",header);
            frame.add("parameter",parameter);
            frame.add("payload",payload);
            System.out.println("frame:\n" + frame.toString());
            webSocket.send(frame.toString());


        }


        ).start();
    }

    //重写onmessage

    @Override
    public void onMessage(WebSocket webSocket, String text) {
        super.onMessage(webSocket, text);
        System.out.println("text:\n" + text);
        ResponseData responseData = json.fromJson(text,ResponseData.class);
        synchronized (LOCK) {
            try {
                //        System.out.println("code:\n" + responseData.getHeader().get("code"));
                if (0 == responseData.getHeader().get("code").getAsInt()) {
                    System.out.println("###########");
                    System.out.println("getStatus: " + responseData.getHeader().get("status").getAsInt());
                    if (2 != responseData.getHeader().get("status").getAsInt()) {
                        System.out.println("****************");
                        Payload pl = json.fromJson(responseData.getPayload(), Payload.class);
                        JsonArray temp = (JsonArray) pl.getChoices().get("text");
                        JsonObject jo = (JsonObject) temp.get(0);
                        answer += jo.get("content").getAsString();
//                System.out.println(answer);
                    } else {
                        Payload pl1 = json.fromJson(responseData.getPayload(), Payload.class);
                        JsonObject jsonObject = (JsonObject) pl1.getUsage().get("text");
                        int prompt_tokens = jsonObject.get("prompt_tokens").getAsInt();
                        JsonArray temp1 = (JsonArray) pl1.getChoices().get("text");
                        JsonObject jo = (JsonObject) temp1.get(0);
                        answer += jo.get("content").getAsString();
                        System.out.println("返回结果为：\n" + answer);

                        if (INSTANCE.redisTemplate.hasKey("gpt:websocket:1")) {
                            DmWebSocketMessageVo message = (DmWebSocketMessageVo) INSTANCE.redisTemplate.opsForValue().get("gpt:websocket:1");
                            if (StringUtils.isNotEmpty(message.getTemplate()) && message.getTemplate().equals("birthday")) {
                                JSONObject birthdayJo = new JSONObject();
                                birthdayJo.put("content", answer);
                                birthdayJo.put("timestamp", message.getFormat().get("timestamp"));
                                INSTANCE.stringRedisTemplate.opsForHash().put("group:nlp" + ":" + message.getFormat().getString("orderId"), "birthday", birthdayJo.toString());
                                INSTANCE.redisTemplate.delete("gpt:websocket:1");
                                return;
                            }
                            if (StringUtils.isNotEmpty(message.getTemplate()) && message.getTemplate().equals("hireDate")) {
                                JSONObject birthdayJo = new JSONObject();
                                birthdayJo.put("content", answer);
                                birthdayJo.put("timestamp", message.getFormat().get("timestamp"));
                                INSTANCE.stringRedisTemplate.opsForHash().put("group:nlp" + ":" + message.getFormat().getString("orderId"), "hireDate", birthdayJo.toString());
                                INSTANCE.redisTemplate.delete("gpt:websocket:1");
                                return;
                            }
                            JSONObject preWebsocketJo = message.getFormat();
                            JSONObject meetingJo = new JSONObject();
                            meetingJo.put("timestamp",preWebsocketJo.get("timestamp"));
                            meetingJo.put("content",answer);
                            INSTANCE.stringRedisTemplate.opsForHash().put("group:nlp" + ":" + preWebsocketJo.getString("orderId"), "meeting", meetingJo.toString());
                            INSTANCE.redisTemplate.delete("gpt:websocket:1");

                        }else {
                            // 添加缓存
                            INSTANCE.stringRedisTemplate.opsForValue().set("group:websocket:content", answer);
                            LOCK.notifyAll();
                        }

//                    webSocket.close(3,"客户端主动断开链接");
                        //webSocket.close(1000,"客户端主动断开链接");

                    }

                } else {
                    System.out.println("返回结果错误：\n" + responseData.getHeader().get("code") + responseData.getHeader().get("message"));
                    LOCK.notifyAll();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    //重写onFailure

    @Override
    public void onFailure(WebSocket webSocket, Throwable t, Response response) {
        super.onFailure(webSocket, t, response);
        System.out.println(response);
    }



    class ResponseData{
        private  JsonObject header;
        private  JsonObject payload;

        public JsonObject getHeader() {
            return header;
        }

        public JsonObject getPayload() {
            return payload;
        }
    }

    class Header{
        private int code ;
        private String message;
        private String sid;
        private String status;

        public int getCode() {
            return code;
        }

        public String getMessage() {
            return message;
        }

        public String getSid() {
            return sid;
        }

        public String getStatus() {
            return status;
        }
    }

    class Payload{
        private JsonObject choices;
        private JsonObject usage;

        public JsonObject getChoices() {
            return choices;
        }

        public JsonObject getUsage() {
            return usage;
        }
    }

    class Choices{
        private int status;
        private int seq;
        private JsonArray text;

        public int getStatus() {
            return status;
        }

        public int getSeq() {
            return seq;
        }

        public JsonArray getText() {
            return text;
        }
    }






}
