package com.tencent.wework;

import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gree.mall.manager.constant.ChatMessageConstant;
import com.gree.mall.manager.constant.Constant;
import com.gree.mall.manager.utils.oss.OSSUtil;
import com.gree.mall.manager.utils.wecom.RSAUtil;
import com.tencent.wework.dto.ChatDataDTO;
import com.tencent.wework.dto.ChatDataResultDTO;
import com.tencent.wework.dto.ChatMessageDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.security.PrivateKey;
import java.util.*;

/**
 * Create By IntelliJ IDEA
 *
 * @author: change
 */
@Slf4j
public class FinanceClient {

    private static final String FILE_BASE_PATH;

    static {
        String osName = System.getProperties().getProperty("os.name");
        if (osName.toUpperCase().contains("WIN")) {
            FILE_BASE_PATH = "C:";
        } else {
            FILE_BASE_PATH = "/tmp/file";
        }
        try {
            File file = new File(FILE_BASE_PATH);
            if (!file.exists()) {
                FileUtils.forceMkdir(file);
            }
        } catch (Exception e) {
            log.error("创建文件目录失败：", e);
        }
    }

    private long sdk;
    private String privateKey;

    private FinanceClient() {

    }

    /**
     * 创建FinanceClient对象
     *
     * @param corpId     企业id
     * @param secret     企业secret
     * @param privateKey 私钥
     * @return FinanceClient对象
     */
    public static FinanceClient newInstance(String corpId, String secret, String privateKey) {
        long sdk = Finance.NewSdk();
        Finance.Init(sdk, corpId, secret);

        FinanceClient financeClient = new FinanceClient();
        financeClient.privateKey = privateKey;
        financeClient.sdk = sdk;

        return financeClient;
    }

    /**
     * 获取聊天记录列表
     *
     * @param seq   查询偏移量
     * @param limit 查询条数
     * @return 聊天记录列表
     */
    public List<ChatMessageDTO> getChatMessageList(long seq, long limit) {
        List<ChatDataDTO> chatDataList = this.getChatDataList(seq, limit);
        if (CollectionUtils.isEmpty(chatDataList)) {
            return Collections.emptyList();
        }

        List<ChatMessageDTO> chatMessageDTOList = new ArrayList<>();
        for (ChatDataDTO chatDataDTO : chatDataList) {
            ChatMessageDTO chatMessageDTO = this.convertChatData2ChatMessage(chatDataDTO);
            if (StringUtils.isEmpty(chatMessageDTO.getAction())){
                continue;
            }
            chatMessageDTOList.add(chatMessageDTO);
        }
        return chatMessageDTOList;
    }

    /**
     * 获取chatData列表
     *
     * @param seq   查询偏移量
     * @param limit 查询条数
     * @return chatData列表
     */
    private List<ChatDataDTO> getChatDataList(long seq, long limit) {
        long slice = Finance.NewSlice();
        int ret = Finance.GetChatData(sdk, seq, limit, "", "", 100, slice);
        if (ret != 0) {
            log.error("获取企业微信聊天记录失败，ret：【{}】", ret);
            return Collections.emptyList();
        }
        String result = Finance.GetContentFromSlice(slice);
        ChatDataResultDTO chatDataResultDTO = JSON.parseObject(result, ChatDataResultDTO.class);

        if (chatDataResultDTO.isSuccess()) {
            return chatDataResultDTO.getChatDataList();
        } else {
            log.error("获取企业微信聊天记录失败，错误码为：【{}】，错误信息为：【{}】", chatDataResultDTO.getErrCode(), chatDataResultDTO.getErrMsg());
            return Collections.emptyList();
        }
    }

    /**
     * 将chatData对象转换为chatMessage
     *
     * @param chatDataDTO ChatData对象
     * @return ChatMessage对象
     */
    private ChatMessageDTO convertChatData2ChatMessage(ChatDataDTO chatDataDTO) {
        ChatMessageDTO chatMessageDTO = new ChatMessageDTO();
        chatMessageDTO.setSeq(chatDataDTO.getSeq());
        chatMessageDTO.setMsgId(chatDataDTO.getMsgId());


        String text = decryptData(chatDataDTO.getEncryptRandomKey(), chatDataDTO.getEncryptChatMsg());

        if (StringUtils.isNotBlank(text)) {
            JSONObject jsonObject = JSON.parseObject(text);
            chatMessageDTO.setAction(jsonObject.getString("action"));
            chatMessageDTO.setMsgType(jsonObject.getString("msgtype"));
            Long msgTimeStamp = jsonObject.getLong("msgtime");
            if (msgTimeStamp != null) {
                chatMessageDTO.setMsgTime(new Date(msgTimeStamp));
            }

            chatMessageDTO.setFrom(jsonObject.getString("from"));
            String toListStr = jsonObject.getString("tolist");
            if (StringUtils.isNotBlank(toListStr)) {
                chatMessageDTO.setToList(JSON.parseArray(toListStr, String.class));
            }
            chatMessageDTO.setRoomId(jsonObject.getString("roomid"));

            JSONObject bodyJsonObject;
            String msgType = chatMessageDTO.getMsgType();
            if (Objects.equals(msgType, Constant.ChatMessage.MSG_TYPE_DOC)) {
                bodyJsonObject = jsonObject.getJSONObject("doc");
            } else if (Objects.equals(msgType, Constant.ChatMessage.MSG_TYPE_EXTERNAL_RED_PACKET)) {
                bodyJsonObject = jsonObject.getJSONObject("redpacket");
            } else {
                bodyJsonObject = jsonObject.getJSONObject(msgType);
            }
            if (bodyJsonObject != null) {
                chatMessageDTO.setBody(bodyJsonObject.toJSONString());
            }
        }

        return chatMessageDTO;
    }

    /**
     * 解析加密的消息
     *
     * @param encryptRandomKey 企业微信返回的randomKey
     * @param encryptChatMsg   加密的消息
     * @return 解密后的消息体
     */
    private String decryptData(String encryptRandomKey, String encryptChatMsg) {
        try {

            //获取私钥
            PrivateKey privateKeyObj = RSAUtil.getPrivateKey(privateKey);
            String str = RSAUtil.decryptRSA(encryptRandomKey, privateKeyObj);

            long slice = Finance.NewSlice();
            int ret = Finance.DecryptData(sdk, str, encryptChatMsg, slice);
            if (ret != 0) {
                log.info("解析企业微信聊天记录失败,ret:【{}】", ret);
                return "";
            }
            String text = Finance.GetContentFromSlice(slice);
            Finance.FreeSlice(slice);

            return text;
        } catch (Exception e) {
            log.error("解密企业微信聊天记录发生异常：", e);
            return "";
        }
    }

    /**
     * 转存文件
     *
     * @param msgType   消息类型
     * @param sdkFileId 文件id
     * @param fileExt   扩展属性
     * @param seq       seq
     * @return 文件路径
     */
    public String transferFile(String msgType, String sdkFileId, String fileExt, long seq) {
        if (StringUtils.isBlank(sdkFileId) || StringUtils.isBlank(msgType)) {
            return "";
        }
        String fileName = fileExt;

        String indexBuf = "";
        while (true) {
            long mediaData = Finance.NewMediaData();
            int ret = Finance.GetMediaData(sdk, indexBuf, sdkFileId, "", "", 60, mediaData);
            if (ret != 0) {
                log.info("获取文件失败，ret:【{}】", ret);
                return "";
            }
            try {

                this.saveToLocal(FILE_BASE_PATH + "/" + fileName, Finance.GetData(mediaData));

                if (Finance.IsMediaDataFinish(mediaData) == 1) {
                    Finance.FreeMediaData(mediaData);
                    // TODO: 上传至文件服务，并删除本地文件
                    OSSUtil.uploadFile(OSSUtil.OSS_TYPE_PIC +fileName,getBytesByFile(FILE_BASE_PATH + "/" + fileName));
                    boolean flag = false;
                    File file = new File(FILE_BASE_PATH + "/" + fileName);
                    if (file.exists() && file.isFile() && file.delete())
                        flag = true;
                    else
                        flag = false;

                    return OSSUtil.accessUrl+OSSUtil.OSS_TYPE_PIC +fileName;
                } else {
                    indexBuf = Finance.GetOutIndexBuf(mediaData);
                    Finance.FreeMediaData(mediaData);
                }
            } catch (Exception e) {
                log.error("保存文件失败：", e);
                return "";
            }

        }
    }

    //将文件转换成Byte数组
    public byte[] getBytesByFile(String pathStr) {
        File file = new File(pathStr);
        System.out.println("文件大小为: " + file.length());
        try {
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
            byte[] b = new byte[1024];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            fis.close();
            byte[] data = bos.toByteArray();
            bos.close();
            return data;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public String getSwitchType(String msgType, String sdkFileId, String fileExt, long seq, Integer type, String fileName) {
        String pathFile = "";
        switch (msgType) {
            case "image":
                pathFile = transferFile(msgType, sdkFileId, UUID.randomUUID().toString() + ".jpg", seq);
                break;
            case "voice":
                pathFile = transferFile(msgType, sdkFileId, UUID.randomUUID().toString() + ".amr", seq);
                break;
            case "video":
                pathFile = transferFile(msgType, sdkFileId, UUID.randomUUID().toString() + ".mp4", seq);
                break;
            case "emotion":
                switch (type) {
                    case 1:
                        pathFile = transferFile(msgType, sdkFileId, UUID.randomUUID().toString() + ".gif", seq);
                        break;
                    case 2:
                        pathFile = transferFile(msgType, sdkFileId, UUID.randomUUID().toString() + ".png", seq);
                        break;
                    default:
                        break;
                }

                break;
            case "file":
                pathFile = transferFile(msgType, sdkFileId, fileName, seq);
                break;
            case "meeting_voice_call":
            case "voip_doc_share":
                pathFile = transferFile(msgType, sdkFileId, fileName, seq);
                break;
            default:
                break;
        }
        return pathFile;
    }

    /**
     * 保存到本地
     *
     * @param filePath 文件路径
     * @param bytes    byte数组
     * @throws IOException
     */
    private void saveToLocal(String filePath, byte[] bytes) throws IOException {
        FileOutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(new File(filePath), true);
            outputStream.write(bytes);
        } finally {
            if (outputStream != null) {
                outputStream.close();
            }
        }
    }

}
