package com.ruoyi.web.controller.api;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.mall.domain.Bo.SaveChatRequestMessage;
import com.ruoyi.mall.domain.Bo.SaveMessage;
import com.ruoyi.mall.domain.Chat.*;
import com.ruoyi.mall.domain.MallMemberUser;
import com.ruoyi.mall.service.IMallMemberUserService;
import okhttp3.RequestBody;
import okhttp3.*;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @ClassName 智能对话接口
 * @Description 智能对话接口
 * @Author LHY
 * @Date 2023/10/18
 * @Version 1.0
 **/
@RestController
@RequestMapping("/api/chat")
public class ApiChatNewController {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private IMallMemberUserService mallMemberUserService;

    @Value("${baidu.appId}")
    private String APP_ID;
    @Value("${baidu.appKey}")
    private String APP_KEY;


    // 读取超时为60s
    private static final long READ_TIMEOUT = 60000;
    // 写入超时为60s
    private static final long WRITE_TIMEOUT = 60000;
    // 连接超时为60s
    private static final long CONNECT_TIMEOUT = 60000;

    private static final long CALL_TIMEOUT = 60000;

    private static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder()
            // 设置调用超时时间
            .callTimeout(CALL_TIMEOUT, TimeUnit.MILLISECONDS)
            // 设置读取超时时间
            .readTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS)
            // 设置写超时时间
            .writeTimeout(WRITE_TIMEOUT, TimeUnit.MILLISECONDS)
            // 设置连接超时时间
            .connectTimeout(CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
            .build();
    private static final ObjectMapper objectMapper = new ObjectMapper();



    // 本次对话ID
    private String conversation_id;

     /**对话历史-近到远—分页
     *
     * @param userId 当前对话用户id
     * @return
     */
    @GetMapping("/getChatHistory")
    public AjaxResult getChatHistory(@RequestParam(defaultValue = "1") Integer pageNum,
                                     @RequestParam(defaultValue = "10") Integer pageSize,
                                     @NotNull(message = "Chat.getChatHistory.userId.isNull") Long userId){
        try {
            MallMemberUser memberUser = mallMemberUserService.selectMallMemberUserById(userId);
            if (memberUser == null) {
                return AjaxResult.error("用户信息异常！！！");
            }
            SaveChatRequestMessage requestBody = new SaveChatRequestMessage();
            List<SaveMessage> history = new ArrayList<>();
            //有历史消息
            if(redisTemplate.hasKey("ChatWith" + memberUser.getId())){
                String json =  redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString();
                System.out.println("json:"+json);
                requestBody = JSONUtil.toBean(json, SaveChatRequestMessage.class);
                if(null != requestBody.getSaveMessageList() && requestBody.getSaveMessageList().size()>0){
                    history = requestBody.getSaveMessageList();
                    Collections.reverse(history);
                }
            }
            List<SaveMessage> pageList = history.stream().sorted().skip((pageNum - 1) * pageSize)
                    .limit(pageSize)
                    .collect(Collectors.toList());
            PageInfo<SaveMessage> pageInfo = new PageInfo<SaveMessage>(pageList);
            //获取PageInfo其他参数
            pageInfo.setTotal(history.size());

            int endRow = pageInfo.getEndRow() == 0 ? 0 : (int)((pageNum - 1) * pageSize + pageInfo.getEndRow() + 1);
            pageInfo.setEndRow(endRow);
            boolean hasNextPage = history.size() <= pageSize * pageNum ? false : true;
            pageInfo.setHasNextPage(hasNextPage);
            boolean hasPreviousPage = pageNum == 1 ? false : true;
            pageInfo.setHasPreviousPage(hasPreviousPage);
            pageInfo.setIsFirstPage(!hasPreviousPage);
            boolean isLastPage = (history.size() > pageSize * (pageNum - 1) && history.size() <= pageSize * pageNum) ? true : false;
            pageInfo.setIsLastPage(isLastPage);
            int pages = history.size() % pageSize == 0 ? history.size() / pageSize : (history.size() / pageSize) + 1;
            pageInfo.setNavigateLastPage(pages);
            int[] navigatePageNums = new int[pages];
            for (int i = 1; i < pages; i++) {
                navigatePageNums[i - 1] = i;
            }
            pageInfo.setNavigatepageNums(navigatePageNums);
            int nextPage = pageNum < pages ? pageNum + 1 : 0;
            pageInfo.setNextPage(nextPage);
            pageInfo.setPageNum(pageNum);
            pageInfo.setPageSize(pageSize);
            pageInfo.setPages(pages);
            pageInfo.setPrePage(pageNum - 1);
            pageInfo.setSize(pageInfo.getList().size());
            int starRow = history.size() < pageSize * pageNum ? 1 + pageSize * (pageNum - 1) : 0;
            pageInfo.setStartRow(starRow);
            return AjaxResult.success().put("data", pageInfo);

        }catch (Exception e){
            return AjaxResult.error("获取对话历史异常!");
        }
    }

    /**
     * 调用知识库
     */
    @PostMapping("/chatNew")
    @org.springframework.web.bind.annotation.ResponseBody
    public AjaxResult newChat(@org.springframework.web.bind.annotation.RequestBody Map<String, Object> params){
        //对用户问题的判断
        if (!params.containsKey("question") || StringUtils.isEmpty(params.get("question").toString())) {
            return AjaxResult.error("缺少问题");
        }
        if (!params.containsKey("userId") || StringUtils.isEmpty(params.get("userId").toString())) {
            return AjaxResult.error("缺少用户id");
        }
        if (!params.containsKey("hasVoice") || ObjectUtils.isEmpty(Integer.valueOf(params.get("hasVoice").toString()))){
            return AjaxResult.error("缺少语音状态");
        }
        long userId = Long.parseLong(params.get("userId").toString());
        // 是否有语音0-没有,1-有
        Integer hasVoice = Integer.valueOf(params.get("hasVoice").toString());

        MallMemberUser memberUser = mallMemberUserService.selectMallMemberUserById(userId);
        if (memberUser == null) {
            return AjaxResult.error("用户信息异常！！！");
        }

        String question = params.get("question").toString();
        // 创建存储用saveMessage
        SaveMessage saveMessage = new SaveMessage();
        saveMessage.setRole("user");
        saveMessage.setContent(question);
        saveMessage.setHasVoice(hasVoice);
        if (hasVoice == 1){
            saveMessage.setVoiceUrl(params.get("voiceUrl").toString());
        }

        com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
        jsonObject.put("query", question);
        List<String> plugins = new ArrayList<>();
        plugins.add("uuid-zhishiku");
        //plugins.add("uuid-weatherforecast");
        //jsonObject.put("plugins", plugins);
        //jsonObject.put("verbose", false);


        // 创建存储类
        SaveChatRequestMessage saveChatRequestMessage = new SaveChatRequestMessage();
        ArrayList<Message> historyList = new ArrayList<>();
        // 查询是否有记录
        if(redisTemplate.hasKey("ChatWith" + memberUser.getId())){
            String json =  redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString();
            saveChatRequestMessage = JSONUtil.toBean(json, SaveChatRequestMessage.class);
            // 记录信息复制到请求参数中
            List<SaveMessage> saveMessageList = saveChatRequestMessage.getSaveMessageList();

            if (!saveMessageList.isEmpty()){
                List<SaveMessage> shortList = new ArrayList<>();
                int size = saveMessageList.size();
                if ( size >= 2){
                    shortList.add(saveMessageList.get(size - 2));
                    shortList.add(saveMessageList.get(size - 1));
                    for (SaveMessage saveMessageHistory : shortList) {
                        Message m = BeanUtil.copyProperties(saveMessageHistory, Message.class);
                        historyList.add(m);
                    }
                }

            }
        }
        //将新的问题添加到消息上下文
        jsonObject.put("history", historyList);
        // 新信息添加保存
        saveChatRequestMessage.addSaveMessage(saveMessage);
        try {
            BaiduAppResponse qaq = qaq(question,memberUser);
            if (StringUtils.isNotBlank(qaq.getAnswer())) {
                Message assistant = new Message("assistant", qaq.getAnswer());
                // // 存储信息
                SaveMessage saveAnswer = BeanUtil.copyProperties(assistant, SaveMessage.class);
                saveAnswer.setHasVoice(hasVoice);

                saveChatRequestMessage.addSaveMessage(saveAnswer);

                // redis 存储
                if (redisTemplate.hasKey("ChatWith" + memberUser.getId())) {
                    redisTemplate.getExpire("ChatWith" + memberUser.getId());
                    redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).set(JSONUtil.toJsonStr(saveChatRequestMessage), 30, TimeUnit.DAYS);
                } else {
                    redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).set(JSONUtil.toJsonStr(saveChatRequestMessage), 30, TimeUnit.DAYS);
                }
                logger.info("存入redis：" + redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString());
                List<SaveMessage> newChat = new ArrayList<>();
                newChat.add(saveMessage);
                newChat.add(saveAnswer);
                return AjaxResult.success(newChat);
            } else {
                logger.error("对话返回结果为空");
                return AjaxResult.error("对话失败!");
            }

        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("对话失败!");
        }

    }

    /**
     * 提问且获取消息
     */
    public BaiduAppResponse qaq(String question,MallMemberUser memberUser) throws Exception {
        // 没有创建回话则创建。
        if (conversation_id == null || "".equals(conversation_id)) {
            createConversation(memberUser.getId());
        }
        // 提问
        logger.info("提问千帆App：" + question);
        MediaType mediaType = MediaType.parse("application/json");
        // 消息体
        String json = objectMapper.writeValueAsString(new BaiduAppRequest(APP_ID, question, conversation_id));
        RequestBody body = RequestBody.create(mediaType, json);
        // 请求
        Request request = new Request.Builder()
                .url("https://qianfan.baidubce.com/v2/app/conversation/runs")
                .method("POST", body)
                .addHeader("Content-Type", "application/json")
                .addHeader("X-Appbuilder-Authorization", "Bearer " + APP_KEY)
                .build();
        Response response = HTTP_CLIENT.newCall(request).execute();
        // 获取消息
        String res = response.body().string();
        logger.info("HTTP请求千帆App回复：" + res);
        BaiduAppResponse baiduAppResponse = objectMapper.readValue(res, BaiduAppResponse.class);
        logger.info("千帆App回复对象：" + JSONUtil.toJsonStr(baiduAppResponse));
        logger.info("千帆App回复：" + baiduAppResponse.getAnswer());
        return baiduAppResponse;
    }

    /**
     * 创建和百度千帆AppBuilder的对话
     */
    private void createConversation(Long userId) throws IOException {

        Object object = redisTemplate.boundValueOps("conversation_id_" + userId).get();
        if (ObjectUtils.isNotEmpty(object)){
            conversation_id = object.toString();
        }else {
            MediaType mediaType = MediaType.parse("application/json");
            RequestBody body = RequestBody.create(mediaType, "{\"app_id\":\"" + APP_ID + "\"}");
            Request request = new Request.Builder()
                    .url("https://qianfan.baidubce.com/v2/app/conversation")
                    .method("POST", body)
                    .addHeader("Content-Type", "application/json")
                    .addHeader("X-Appbuilder-Authorization", "Bearer " + APP_KEY)
                    .build();
            Response response = HTTP_CLIENT.newCall(request).execute();
            String res = response.body().string();
            logger.info("百度千帆AppBuilder 创建对话响应：" + res);
            conversation_id = objectMapper.readTree(res).get("conversation_id").asText();
        }
        redisTemplate.boundValueOps("conversation_id_" + userId).set(conversation_id, 30, TimeUnit.DAYS);
    }

}
