package cn.teammodel.ai.deepseek;

import cn.teammodel.ai.SparkGptClient;
import cn.teammodel.ai.SseHelper;
import cn.teammodel.ai.cache.HistoryCache;
import cn.teammodel.ai.domain.SparkChatRequestParam;
import cn.teammodel.common.ErrorCode;
import cn.teammodel.common.PK;
import cn.teammodel.config.exception.ServiceException;
import cn.teammodel.model.dto.ai.ChatCompletionReqDto;
import cn.teammodel.model.dto.ai.deepseek.DeepSeekChatRequestDto;
import cn.teammodel.model.dto.ai.deepseek.DeepSeekChatResponse;
import cn.teammodel.model.dto.ai.deepseek.ChatReqDto;
import cn.teammodel.model.entity.ai.ChatSession;
import cn.teammodel.repository.ChatSessionRepository;
import cn.teammodel.utils.JsonUtil;
import com.azure.cosmos.models.CosmosPatchOperations;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.google.gson.Gson;
import com.sun.org.apache.bcel.internal.generic.NEW;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import okio.Buffer;
import okio.BufferedSource;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
public class DeepSeekClient {
    public static final String API_Key;
    public static final String API_Url;
    public static String API_Model;
    //public static String API_Model_Url;
    //public static String API_Model_Reasoner;

    @Resource
    private static ChatSessionRepository chatSessionRepository;

    private static final ExecutorService executorService = Executors.newCachedThreadPool();
    private static final ObjectMapper objectMapper = new ObjectMapper();
    /**
     * 读取配置文件 读取key 和url
     */
    static {
        Properties props = new Properties();
        try {
            InputStream is = DeepSeekClient.class.getResourceAsStream("/DeepSeekConfig.properties");
            props.load(is);
            API_Key = props.getProperty("key");
            API_Url = props.getProperty("url");
            API_Model = props.getProperty("model");
            //API_Model_Url = props.getProperty("modelReasonerUrl");
            //API_Model_Reasoner = props.getProperty("modelReasoner");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 提问题   测试使用
     * @param mssage
     */
    private static Map<String, Object> ask(ChatReqDto mssage)
    {
        Map<String, Object> mapper = new HashMap<>();
        //创建消息列表
        List<ChatReqDto> msg = new ArrayList<>();
        msg.add(mssage);

        //构建请求头
        DeepSeekChatRequestDto requestBody = new DeepSeekChatRequestDto();
        requestBody.setModel(API_Model);
        requestBody.setMessages(msg);
        requestBody.setTemperature(0);
        requestBody.setMax_tokens(1024);

        long startTime = System.currentTimeMillis();
        //发起请求
        DeepSeekChatResponse response = SendRequests(requestBody);
        //Map<String, Object> response = SendRequest(requestBody);
        Long endTime = System.currentTimeMillis();
        //思考耗时 秒
        long time = (endTime-startTime)/1000;
        response.setWasteTime(time);
        return mapper;

    }

    /***
     * OkHttpClient 方式请求
     * 返回请求结果 转 实体有问题
     * @param requestBody
     * @return
     */
    public static DeepSeekChatResponse SendRequests(DeepSeekChatRequestDto requestBody)
    {
        DeepSeekChatResponse chatResponse = new DeepSeekChatResponse();
        //OkHttpClient client = new OkHttpClient().newBuilder().connectTimeout(60, TimeUnit.SECONDS).build();//设置连接超时时间 1分钟
        OkHttpClient client = new OkHttpClient().newBuilder().build();//设置连接超时时间 1分钟


        MediaType mediaType = MediaType.parse("application/json");
        //String  content = "{\n  \"messages\": [\n    {\n      \"content\": \"You are a helpful assistant\",\n      \"role\": \"system\"\n    },\n    {\n      \"content\": \"Hi\",\n      \"role\": \"user\"\n    }\n  ],\n  \"model\": \"deepseek-chat\",\n  \"frequency_penalty\": 0,\n  \"max_tokens\": 2048,\n  \"presence_penalty\": 0,\n  \"response_format\": {\n    \"type\": \"text\"\n  },\n  \"stop\": null,\n  \"stream\": false,\n  \"stream_options\": null,\n  \"temperature\": 1,\n  \"top_p\": 1,\n  \"tools\": null,\n  \"tool_choice\": \"none\",\n  \"logprobs\": false,\n  \"top_logprobs\": null\n}";
        String content = JsonUtil.convertToJson(requestBody);

        RequestBody body = RequestBody.create(mediaType, content);
        Request request = new Request.Builder()
                .url(API_Url)
                .method("POST", body)
                .addHeader("Content-Type", "application/json")
                .addHeader("Accept", "application/json")
                .addHeader("Authorization", "Bearer "+API_Key)
                .build();
        ObjectMapper objectMapper = new ObjectMapper();
        try(Response response = client.newCall(request).execute()) {
            if (response.isSuccessful() && response.body() != null) {
                StringBuilder responseBody = new StringBuilder();
                try (BufferedSource source = response.body().source()) {
                    Buffer buffer = new Buffer();
                    while (source.read(buffer, 2048) != -1) {
                        // 处理流式数据
                        String chunk = buffer.readUtf8();
                        if (chunk.startsWith("data:") && !chunk.contains("data: [DONE]")) {
                            String[] split = chunk.split("data:");
                            for (String result : split) {
                                if (StringUtils.hasLength(result) && StringUtils.hasLength(result.trim())) {
                                    JsonNode jsonNode = objectMapper.readTree(result);
                                    if (!ObjectUtils.isEmpty(jsonNode.get("choices"))) {
                                        JsonNode delta = jsonNode.get("choices").get(0).get("delta");
                                        log.debug("Delta Content: {}", delta.get("content").asText());
                                        responseBody.append(delta.get("content").asText());
                                    }
                                }
                            }
                        }
                    }
                }


                String responseBody1 = response.body().string();
                // 使用 Gson 将 JSON 字符串转换为 MyEntity 对象
                Gson gson = new Gson();
                chatResponse = gson.fromJson(responseBody1, DeepSeekChatResponse.class);
                // 确保关闭响应体以释放资源
                response.body().close();
                chatResponse.setCode(200);
                chatResponse.setMsg("成功");
            } else {
                chatResponse.setCode( response.code());
                chatResponse.setMsg(response.body().string());
            }
        } catch (IOException e) {
            if (e.getMessage().equals("Connection timed out") || e.getMessage().equals("timeout"))
            {
                chatResponse.setCode(408);
                chatResponse.setMsg("请求DeepSeek服务器超时");
            }else {
                chatResponse.setCode( 500);
                chatResponse.setMsg(e.getMessage());
            }
        }
        return chatResponse;
    }


    /**
     * OkHttpClient 方式请求 流式返回
     * @param requestBody
     * @return
     */
    public static SseEmitter SendRequestsEmitter(DeepSeekChatRequestDto requestBody)
    {
        SseEmitter sseEmitter = new SseEmitter(-1L);
        //OkHttpClient client = new OkHttpClient().newBuilder().connectTimeout(60, TimeUnit.SECONDS).build();//设置连接超时时间 1分钟
        OkHttpClient client = new OkHttpClient().newBuilder().build();//

        MediaType mediaType = MediaType.parse("application/json");
        //String  content = "{\n  \"messages\": [\n    {\n      \"content\": \"You are a helpful assistant\",\n      \"role\": \"system\"\n    },\n    {\n      \"content\": \"Hi\",\n      \"role\": \"user\"\n    }\n  ],\n  \"model\": \"deepseek-chat\",\n  \"frequency_penalty\": 0,\n  \"max_tokens\": 2048,\n  \"presence_penalty\": 0,\n  \"response_format\": {\n    \"type\": \"text\"\n  },\n  \"stop\": null,\n  \"stream\": false,\n  \"stream_options\": null,\n  \"temperature\": 1,\n  \"top_p\": 1,\n  \"tools\": null,\n  \"tool_choice\": \"none\",\n  \"logprobs\": false,\n  \"top_logprobs\": null\n}";
        String content = JsonUtil.convertToJson(requestBody);

        RequestBody body = RequestBody.create(mediaType, content);
        Request request = new Request.Builder()
                .url(API_Url)
                .method("POST", body)
                .addHeader("Content-Type", "application/json")
                .addHeader("Accept", "application/json")
                .addHeader("Authorization", "Bearer "+API_Key)
                .build();
        ObjectMapper objectMapper = new ObjectMapper();
        try(Response response = client.newCall(request).execute()) {
            if (response.isSuccessful() && response.body() != null) {
                StringBuilder responseBody = new StringBuilder();
                try (BufferedSource source = response.body().source()) {
                    Buffer buffer = new Buffer();
                    while (source.read(buffer, 2048) != -1) {
                        // 处理流式数据
                        String chunk = buffer.readUtf8();
                        if (chunk.startsWith("data:") && !chunk.contains("data: [DONE]")) {
                            String[] split = chunk.split("data:");
                            for (String result : split) {
                                if (StringUtils.hasLength(result) && StringUtils.hasLength(result.trim())) {
                                    JsonNode jsonNode = objectMapper.readTree(result);
                                    if (!ObjectUtils.isEmpty(jsonNode.get("choices"))) {
                                        JsonNode delta = jsonNode.get("choices").get(0).get("delta");
                                        log.debug("Delta Content: {}", delta.get("content").asText());
                                        sseEmitter.send(delta);
                                    }
                                }
                            }
                        }
                    }
                }catch (IOException e) {
                    sseEmitter.completeWithError(e);
                }

            } else {
                sseEmitter.completeWithError(new Exception("请求DeepSeek服务器失败"));
            }
        } catch (IOException e) {
            sseEmitter.completeWithError(e);
        }
        return sseEmitter;
    }

    /**
     * HttpClient 方式请求
     * @param chatCompletionReqDto
     * @return
     */
    public static SseEmitter HttpClientSendRequests(ChatCompletionReqDto chatCompletionReqDto){
        SseEmitter emitter = new SseEmitter(-1L);
        List<ChatReqDto> msg = new ArrayList<>();
        msg.add(new ChatReqDto(chatCompletionReqDto.getSessionId(), "user", chatCompletionReqDto.getText()));
        //构建请求头
        DeepSeekChatRequestDto requestBody = new DeepSeekChatRequestDto();
        requestBody.setModel(DeepSeekClient.API_Model);
        requestBody.setMessages(msg);
        requestBody.setTemperature(0);
        requestBody.setStream(true);

        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            // 创建HttpPost对象
            HttpPost httpPost = new HttpPost(API_Url);
            //添加请求头
            httpPost.setHeader("Content-Type", "application/json");
            httpPost.setHeader("Accept", "application/json");
            httpPost.setHeader("Authorization", "Bearer " + API_Key);

            requestBody.setStream(true);
            // 设置请求体
            String jsonContent = JsonUtil.convertToJson(requestBody);
            httpPost.setEntity(new StringEntity(jsonContent, ContentType.create("application/json", "UTF-8")));
            StringBuilder responseBody = new StringBuilder();
            try (CloseableHttpResponse response = httpClient.execute(httpPost);
                 BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), StandardCharsets.UTF_8))) {
                String line;
                StringBuilder strContent = new StringBuilder();
                while ((line = reader.readLine()) != null) {
                    if (line.startsWith("data: ")) {
                        String jsonData = line.substring(6);
                        if ("[DONE]".equals(jsonData)) {
                            //SseHelper.send(emitter, "[DONE]");
                            emitter.send("[DONE]");
                            // 更新历史会话记录
                            ChatSession.Message message = ChatSession.Message.of(chatCompletionReqDto.getText(), strContent.toString(),chatCompletionReqDto.getModel());
                            HistoryCache.updateContext(chatCompletionReqDto.getSessionId(), message);
                            CosmosPatchOperations options = CosmosPatchOperations.create()
                                    .replace("/updateTime", Instant.now().toEpochMilli())
                                    .add("/history/-", message);
                            chatSessionRepository.save(chatCompletionReqDto.getSessionId(), PK.of(PK.CHAT_SESSION), ChatSession.class, options);
                            break;
                        }
                        JsonNode node = objectMapper.readTree(jsonData);
                        String content = node.path("choices")
                                .path(0)
                                .path("delta")
                                .path("content")
                                .asText("");
                        if (!content.isEmpty()) {
                            responseBody.append(content);
                            strContent.append(content);
                            emitter.send(content);
                        }
                    }
                }
                emitter.complete();
            }catch (Exception e)
            {
                emitter.completeWithError(e);
            }
        }catch (Exception e) {
            emitter.completeWithError(e);
        }

        return emitter;
    }

    /***
     * HttpClient 方式请求
     * @param requestBody
     * @return
     */
    public static Map<String, Object> SendRequest(DeepSeekChatRequestDto requestBody) {
        Map<String, Object> mapper = new HashMap<>();
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            // 创建HttpPost对象
            HttpPost httpPost = new HttpPost(API_Url);
            //添加请求头
            httpPost.setHeader("Content-Type", "application/json");
            httpPost.setHeader("Accept", "application/json");
            httpPost.setHeader("Authorization", "Bearer " +API_Key);

            // 设置请求体
            String jsonContent = JsonUtil.convertToJson(requestBody);
            httpPost.setEntity(new StringEntity(jsonContent, ContentType.create("application/json", "UTF-8")));

            // 发送请求
            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                // 获取响应实体
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    // 解析响应内容
                    String jsonString = EntityUtils.toString(entity);
                    ObjectMapper objectMapper = new ObjectMapper();
                    mapper = objectMapper.readValue(jsonString, TypeFactory.defaultInstance().constructMapType(Map.class, String.class, Object.class));
                }

                // 检查响应状态码
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode != 200) throw new RuntimeException("Failed : HTTP error code : " + statusCode);
            } catch (IOException e) {
                throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据解析异常");
            }

        } catch (IOException e) {
            throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "请求头异常"+e.getMessage());
        }
        //TODO 请求接口
        return mapper;
    }
}
