


package com.ai.da.service.impl;

import cn.hutool.core.exceptions.ExceptionUtil;
import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.common.enums.LibraryLevel1TypeEnum;
import com.ai.da.common.utils.CopyUtil;
import com.ai.da.common.utils.MD5Utils;
import com.ai.da.common.utils.MinioUtil;
import com.ai.da.common.utils.S3Util;
import com.ai.da.mapper.primary.AccountMapper;
import com.ai.da.mapper.primary.LibraryMapper;
import com.ai.da.mapper.primary.entity.Account;
import com.ai.da.mapper.primary.entity.ChatRobot;
import com.ai.da.mapper.primary.ChatRobotMapper;
import com.ai.da.mapper.primary.entity.Library;
import com.ai.da.model.dto.ChatFlushDTO;
import com.ai.da.model.dto.ChatRobotLibraryDTO;
import com.ai.da.model.dto.ChatSendDTO;
import com.ai.da.model.vo.ChatRobotLibraryVO;
import com.ai.da.model.vo.ChatRobotVO;
import com.ai.da.service.ChatRobotService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.minio.errors.MinioException;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @author aida
 * @version 1.0
 * @project ChatRobot
 * @description 请求python Chat Stream 接口服务实现类
 * @date 2023/7/10 10:41:45
 */
@Slf4j
@Service
public class ChatRobotServiceImpl extends ServiceImpl<ChatRobotMapper, ChatRobot> implements ChatRobotService {

    //    @Value("")
    String chatStreamUrl = "http://18.167.251.121:6789/api/chat_stream";
    String chatBufferFlushUrl = "http://18.167.251.121:6789/api/chat_flush";

    RestTemplate restTemplate = new RestTemplate();

    @Resource
    private ChatRobotMapper chatRobotMapper;

    @Resource
    private MinioUtil minioUtil;

    @Resource
    private LibraryMapper libraryMapper;

    @Value("${minio.bucketName.sysImage}")
    private String sysImage;

    @Resource
    private AccountMapper accountMapper;

    Gson gson = new GsonBuilder().create();
    private final ExecutorService executorService = Executors.newSingleThreadExecutor();
    Integer timeout = 99999999;

    @Value("${access.python.ip:''}")
    private String accessPythonIp;
    @Value("${access.python.port:''}")
    private String accessPythonPort;
    @Value("${access.python.address}")
    private String fastApiPythonAddress;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ChatRobotVO sendMessageToChatRobot(ChatSendDTO chatSendDTO) {
//        SseEmitter emitter = new SseEmitter();
//        String requestBody = gson.toJson(chatSendDTO);
//        executorService.execute(() -> {
//            try {
//                // 这里根据你的业务逻辑，从服务获取数据
//                // 示例：从服务获取数据并逐条发送给客户端
//                URL urlObj = new URL(chatStreamUrl);
//                HttpURLConnection connection = (HttpURLConnection) urlObj.openConnection();
//                connection.setConnectTimeout(timeout);
//                connection.setReadTimeout(timeout);
//                connection.setRequestMethod("POST");
//                connection.setRequestProperty("Content-Type", "application/json");
//                connection.setDoOutput(true);
//
//                OutputStream outputStream = connection.getOutputStream();
//                outputStream.write(requestBody.getBytes());
//                outputStream.flush();
//                outputStream.close();
//
//                int responseCode = connection.getResponseCode();
//
//                if (responseCode == HttpURLConnection.HTTP_OK) {
//                    BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
//                    String line;
//                    while ((line = reader.readLine()) != null) {
//                        log.info(line);
//
//                        emitter.send(line);
////                        Thread.sleep(1000);
//
//                    }
//                    reader.close();
//                } else {
//                    System.out.println("Request failed with status code: " + responseCode);
//                }
//
//                connection.disconnect();
//                emitter.complete();
//            } catch (Exception e) {
//                emitter.completeWithError(e);
//            }
//        });
//        return emitter;

//        AuthPrincipalVo userInfo = UserContext.getUserHolder();
//        chatSendDTO.setUser_id(userInfo.getId());
//        chatSendDTO.setUser_id(chatSendDTO.getUser_id());
        OkHttpClient client = new OkHttpClient().newBuilder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .pingInterval(5, TimeUnit.SECONDS)//websocket轮训间隔(单位:秒)
                .readTimeout(60, TimeUnit.SECONDS)//读取超时(单位:秒)
                .writeTimeout(60, TimeUnit.SECONDS)//写入超时(单位:秒)
                .build();
        MediaType mediaType = MediaType.parse("application/json");
        //关闭FastJson的引用检测 防止出现$ref 现象
        String param = JSON.toJSONString(chatSendDTO, SerializerFeature.DisableCircularReferenceDetect);
        log.info("chatRobot请求python 参数:####{}", param);
        RequestBody body = RequestBody.create(mediaType, param);
        Request request = new Request.Builder()
//                .url("http://127.0.0.1:8000/api/chat_robot")
                .url(accessPythonIp + ":" + accessPythonPort + "/api/chat_robot")
                .method("POST", body)
                .addHeader("Content-Type", "application/json")
                .build();
        Response response = null;
        try {
            response = client.newCall(request).execute();
        } catch (IOException ioException) {
            log.error("PythonService##chatRobot异常###{}", ExceptionUtil.getThrowableList(ioException));
        }
        if (Objects.isNull(response)) {
            log.error("PythonService##chatRobot异常###{}", "response is empty!");
            throw new BusinessException("chat-bot.interface.exception");
        }
        if (response.isSuccessful()) {
            try {
                String responseBody = response.body().string();
                JSONObject responseObject = JSON.parseObject(responseBody);
                JSONObject data = responseObject.getJSONObject("data");
                log.info(String.valueOf(data));
                if (null != data) {
                    ChatRobot chatRobot = new ChatRobot();
                    chatRobot.setResponseType(data.getString("response_type"));
                    chatRobot.setCompletionTokens(data.getLong("completion_tokens"));
                    chatRobot.setInput(data.getString("input"));
                    String output = data.getString("output");
                    chatRobot.setOutput(output);
                    chatRobot.setPromptTokens(data.getLong("prompt_tokens"));
                    chatRobot.setSessionId(data.getString("session_id"));
                    BigDecimal totalCost = data.getBigDecimal("total_cost");
                    // 校验本次余额够不够
                    ChatRobotVO balance = checkBalance(totalCost, chatSendDTO.getUser_id());
                    if (!Objects.isNull(balance)) return balance;
                    chatRobot.setTotalCost(totalCost);
                    chatRobot.setTotalTokens(data.getLong("total_tokens"));
                    chatRobot.setUserId(chatSendDTO.getUser_id());
                    chatRobot.setCreateTime(LocalDateTime.now());
                    ChatRobotVO chatRobotVO = CopyUtil.copyObject(chatRobot, ChatRobotVO.class);
                    if (null != chatRobotVO.getResponseType() && "image".equals(chatRobotVO.getResponseType())) {
                        List<ChatRobotLibraryVO> chatRobotLibraryVOList = new ArrayList<>();
                        if (output.startsWith("[")) {
                            JSONArray array = JSONArray.parseArray(output);
                            if (array.size() == 0) {
                                chatRobot.setSuccessful(0);
                                chatRobotMapper.insert(chatRobot);
                                chatRobotVO.setOutput("I'm sorry, but I can't process your current request. Please rephrase it differently.");
                            } else {
                                chatRobot.setSuccessful(1);
                                chatRobotMapper.insert(chatRobot);
                                int size = Math.min(array.size(), 4);
                                for (int i = 0; i < size; i++) {
//                                    if (i >= 3) {
//                                        continue;
//                                    }
                                    ChatRobotLibraryVO chatRobotLibraryVO = new ChatRobotLibraryVO();
                                    String bucketName = sysImage;
                                    String prefix = getPrefix(array.getString(i),chatSendDTO.getGender());
                                    String path = prefix;
//                                    String path = prefix + array.getString(i);
                                    if (minioUtil.doesObjectExist(bucketName,path)){
                                        QueryWrapper<Library> qw = new QueryWrapper<>();
                                        qw.lambda().eq(Library::getUrl, bucketName + "/" + path);
                                        qw.lambda().eq(Library::getAccountId, chatSendDTO.getUser_id());
                                        qw.lambda().last("limit 1");
                                        List<Library> libraryList = libraryMapper.selectList(qw);
                                        if (!CollectionUtils.isEmpty(libraryList)) {
                                            chatRobotLibraryVO.setId(libraryList.get(0).getId());
                                        }
                                        String aidaSysImage = minioUtil.getPreSignedUrl(bucketName + "/" + path, 24 * 60);
                                        chatRobotLibraryVO.setUrl(bucketName + "/" + path);
                                        chatRobotLibraryVO.setPresignedUrl(aidaSysImage);
                                        chatRobotLibraryVOList.add(chatRobotLibraryVO);
                                    }
                                }
                                if (!CollectionUtils.isEmpty(chatRobotLibraryVOList)){
                                    chatRobotVO.setChatRobotLibraryList(chatRobotLibraryVOList);
                                }else {
                                    chatRobotVO.setOutput("I'm sorry, but I can't process your current request. Please rephrase it differently.");
                                }
                            }
                        } else {
                            chatRobot.setSuccessful(0);
                            chatRobotMapper.insert(chatRobot);
                            chatRobotVO.setOutput("I'm sorry, but I can't process your current request. Please rephrase it differently.");
                        }
                    } else {
                        chatRobot.setSuccessful(1);
                        chatRobotMapper.insert(chatRobot);
                    }
                    chatRobotVO.setIsTutorial(output.contains("Commencing the systematic tutorial guide now."));
                    return chatRobotVO;
                }
                log.error("ChatRobot response data is null!");
                throw new BusinessException("chat-bot.interface.exception");
            } catch (IOException e) {
                throw new BusinessException("chat-bot.interface.exception");
            }
        }
        log.error("ChatRobot exception! 请求异常：{}", response);
        throw new BusinessException("chat-bot.interface.exception");
    }

    private ChatRobotVO checkBalance(BigDecimal totalCost, Long userId) {
        QueryWrapper<ChatRobot> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        queryWrapper.ge("create_time", LocalDateTime.now().withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0));
        queryWrapper.select("user_id", "SUM(total_cost) as total_cost");
        queryWrapper.groupBy("user_id");
        List<ChatRobot> chatRobots = chatRobotMapper.selectList(queryWrapper);
        if (!CollectionUtils.isEmpty(chatRobots)) {
            BigDecimal totalCostUsed = chatRobots.get(0).getTotalCost();
            Account account = accountMapper.selectById(userId);
            ChatRobot chatRobot = new ChatRobot();
            if (account.getIsTrial() == 3) {
//                if (totalCostUsed.add(totalCost).compareTo(BigDecimal.valueOf(0.1)) > 0) {
                if (totalCostUsed.add(totalCost).compareTo(BigDecimal.valueOf(0.7)) > 0) {
                    String messageFromResource = BusinessException.getMessageFromResource("balance.insufficient.for.trial");
                    chatRobot.setOutput(messageFromResource);
//                    throw new BusinessException("Your balance is insufficient");
                    return CopyUtil.copyObject(chatRobot, ChatRobotVO.class);
                }
            }else {
//                if (totalCostUsed.add(totalCost).compareTo(BigDecimal.valueOf(5)) > 0) {
                if (totalCostUsed.add(totalCost).compareTo(BigDecimal.valueOf(35)) > 0) {
                    String messageFromResource = BusinessException.getMessageFromResource("balance.insufficient.for.paying");
                    chatRobot.setOutput(messageFromResource);
//                    throw new BusinessException("Your balance is insufficient");
                    return CopyUtil.copyObject(chatRobot, ChatRobotVO.class);
                }
            }
        }
        return null;
    }

    @Override
    public String chatBufferFlush(ChatFlushDTO chatFlushDTO) {
        log.info(chatBufferFlushUrl);
        return String.valueOf(restTemplate.postForEntity(chatBufferFlushUrl, chatFlushDTO, String.class));
    }

    @Override
    public Library pictureLikeOrUnLike(ChatRobotLibraryDTO chatRobotLibraryDTO) {
        if (chatRobotLibraryDTO.getId() == null) {
            Library library = new Library();
            library.setAccountId(chatRobotLibraryDTO.getUserId());
            library.setUrl(chatRobotLibraryDTO.getUrl());
            library.setLevel1Type(LibraryLevel1TypeEnum.SKETCH_BOARD.getRealName());
            String[] split = chatRobotLibraryDTO.getUrl().split("/");
            if (split.length == 5) {
                String level3Type = split[2];
                if (level3Type != null && !level3Type.isEmpty()) {
                    library.setLevel3Type(Character.toUpperCase(level3Type.charAt(0)) + level3Type.substring(1));
                }
                String level2Type = split[3];
                if (level2Type != null && !level2Type.isEmpty()) {
                    library.setLevel2Type(Character.toUpperCase(level2Type.charAt(0)) + level2Type.substring(1));
                }
                String name = split[4];
                if (name.contains(".")) {
                    library.setName(name.split("\\.")[0]);
                } else {
                    library.setName(name);
                }
            } else {
                throw new BusinessException("the.path.is.error");
            }

            try {
                library.setMd5(MD5Utils.encryptFile(minioUtil.download(library.getUrl())));
            } catch (MinioException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            library.setCreateDate(new Date());
            libraryMapper.insert(library);
            return library;
        } else {
            libraryMapper.deleteById(chatRobotLibraryDTO.getId());
            return null;
        }
    }

    @Override
    public BigDecimal getBloodBars(Long userId) {
        QueryWrapper<ChatRobot> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        queryWrapper.ge("create_time", LocalDateTime.now().withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0));
        queryWrapper.select("user_id", "SUM(total_cost) as total_cost");
        queryWrapper.groupBy("user_id");
        List<ChatRobot> chatRobots = chatRobotMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(chatRobots)) {
            return BigDecimal.ONE;
        } else {
            Account account = accountMapper.selectById(userId);
//            BigDecimal totalCost = BigDecimal.valueOf(5).subtract(chatRobots.get(0).getTotalCost());
            BigDecimal totalCost = BigDecimal.valueOf(35).subtract(chatRobots.get(0).getTotalCost());
            if (account.getIsTrial() == 1) {
//                totalCost = BigDecimal.valueOf(0.1).subtract(chatRobots.get(0).getTotalCost());
                totalCost = BigDecimal.valueOf(0.7).subtract(chatRobots.get(0).getTotalCost());
                return totalCost.divide(BigDecimal.valueOf(0.1), 4, RoundingMode.HALF_UP);
            }else {
                return totalCost.divide(BigDecimal.valueOf(5), 4, RoundingMode.HALF_UP);
            }
        }
    }

    private String getPrefix(String minioPath,String gender){
        if (minioPath.startsWith("\\male") || minioPath.startsWith("\\female")){
            minioPath = minioPath.replace("\\male\\", "");
            minioPath = minioPath.replace("\\female\\", "").replace("\\", "/");

        }
        if (gender.equals("Male")){
            String substring = minioPath.substring(minioPath.lastIndexOf("/") + 1, minioPath.lastIndexOf("_"));
            String folder = minioPath.substring(0,minioPath.lastIndexOf("/"));
            if ("mens_test".equals(substring)){
                switch (folder){
//                    case "bottom":
//                        minioPath = minioPath.replace("bottom","bottoms");
//                        break;
                    case "top":
                        minioPath = minioPath.replace("top","tops");
                        break;
                    case "outer":
                        minioPath = minioPath.replace("outer","outwear");
                        break;
                }
                return "images/male/" + minioPath;
            }
        }
        return "images/female/" + minioPath;
    }

    public Long getCountByUserAndTime(String startTime, String endTime, List<Long> accountIds){
        QueryWrapper<ChatRobot> queryWrapper = new QueryWrapper<>();
        queryWrapper.gt("create_time", startTime)
                .lt("create_time", endTime)
                .select("count(id) as count");

        if (!accountIds.isEmpty()){
            queryWrapper.in("user_id", accountIds);
        }

        List<Map<String, Object>> result = baseMapper.selectMaps(queryWrapper);
        if (result != null && !result.isEmpty()) {
            Object countObj = result.get(0).get("count");
            return (Long) countObj;
        }else {
            return 0L;
        }
    }

}
