#pragma once

#include <stdint.h>
#include <string>

namespace Tencent {

static const unsigned int kAesKeySize = 32;
static const unsigned int kAesIVSize = 16;
static const unsigned int kEncodingKeySize = 43;
static const unsigned int kRandEncryptStrLen = 16;
static const unsigned int kMsgLen = 4;
static const unsigned int kMaxBase64Size = 1000000000;
enum WXBizMsgCryptErrorCode {
    WXBizMsgCrypt_OK = 0,
    WXBizMsgCrypt_ValidateSignature_Error = -40001,
    WXBizMsgCrypt_ParseXml_Error = -40002,
    WXBizMsgCrypt_ComputeSignature_Error = -40003,
    WXBizMsgCrypt_IllegalAesKey = -40004,
    WXBizMsgCrypt_ValidateCorpid_Error = -40005,
    WXBizMsgCrypt_EncryptAES_Error = -40006,
    WXBizMsgCrypt_DecryptAES_Error = -40007,
    WXBizMsgCrypt_IllegalBuffer = -40008,
    WXBizMsgCrypt_EncodeBase64_Error = -40009,
    WXBizMsgCrypt_DecodeBase64_Error = -40010,
    WXBizMsgCrypt_GenReturnXml_Error = -40011,
};

class WXBizMsgCrypt {
public:
    // 构造函数
    //  @param sToken: 企业微信后台，开发者设置的Token
    //  @param sEncodingAESKey: 企业微信后台，开发者设置的EncodingAESKey
    //  @param sReceiveId: 不同场景含义不同，详见文档
    WXBizMsgCrypt(const std::string &sToken, const std::string &sEncodingAESKey, const std::string &sReceiveId)
        : m_sToken(sToken), m_sEncodingAESKey(sEncodingAESKey), m_sReceiveId(sReceiveId) {
    }
    // 验证URL
    //  @param sMsgSignature: 签名串，对应URL参数的msg_signature
    //  @param sTimeStamp: 时间戳，对应URL参数的timestamp
    //  @param sNonce: 随机串，对应URL参数的nonce
    //  @param sEchoStr: 随机串，对应URL参数的echostr
    //  @param sReplyEchoStr: 解密之后的echostr，当return返回0时有效
    //  @return：成功0，失败返回对应的错误码
    int VerifyURL(const std::string &sMsgSignature, const std::string &sTimeStamp, const std::string &sNonce,
                  const std::string &sEchoStr, std::string &sReplyEchoStr);

    // 检验消息的真实性，并且获取解密后的明文
    // @param sMsgSignature: 签名串，对应URL参数的msg_signature
    // @param sTimeStamp: 时间戳，对应URL参数的timestamp
    // @param sNonce: 随机串，对应URL参数的nonce
    // @param sPostData: 密文，对应POST请求的数据
    // @param sMsg: 解密后的原文，当return返回0时有效
    // @return: 成功0，失败返回对应的错误码
    int DecryptMsg(const std::string &sMsgSignature, const std::string &sTimeStamp, const std::string &sNonce,
                   const std::string &sPostData, std::string &sMsg);

    // 将企业微信回复用户的消息加密打包
    //  @param sReplyMsg:企业微信待回复用户的消息，xml格式的字符串
    //  @param sTimeStamp: 时间戳，可以自己生成，也可以用URL参数的timestamp
    //  @param sNonce: 随机串，可以自己生成，也可以用URL参数的nonce
    //  @param sEncryptMsg: 加密后的可以直接回复用户的密文，包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串,
    //                       当return返回0时有效
    //  return：成功0，失败返回对应的错误码
    int EncryptMsg(const std::string &sReplyMsg, const std::string &sTimeStamp, const std::string &sNonce,
                   std::string &sEncryptMsg);

private:
    std::string m_sToken;
    std::string m_sEncodingAESKey;
    std::string m_sReceiveId;

private:
    // AES CBC
    int AES_CBCEncrypt(const char *sSource, const uint32_t iSize, const char *sKey, unsigned int iKeySize, std::string *poResult);

    int AES_CBCEncrypt(const std::string &objSource, const std::string &objKey, std::string *poResult);

    int AES_CBCDecrypt(const char *sSource, const uint32_t iSize, const char *sKey, uint32_t iKeySize, std::string *poResult);

    int AES_CBCDecrypt(const std::string &objSource, const std::string &objKey, std::string *poResult);

    // base64
    int EncodeBase64(const std::string sSrc, std::string &sTarget);

    int DecodeBase64(const std::string sSrc, std::string &sTarget);

    // genkey
    int GenAesKeyFromEncodingKey(const std::string &sEncodingKey, std::string &sAesKey);

    // signature
    int ComputeSignature(const std::string sToken, const std::string sTimeStamp, const std::string &sNonce,
                         const std::string &sMessage, std::string &sSignature);

    int ValidateSignature(const std::string &sMsgSignature, const std::string &sTimeStamp, const std::string &sNonce,
                          const std::string &sEncryptMsg);

    // get , set data
    void GenRandStr(std::string &sRandStr, uint32_t len);

    void GenNeedEncryptData(const std::string &sReplyMsg, std::string &sNeedEncrypt);

    int GenReturnXml(const std::string &sEncryptMsg, const std::string &sSignature, const std::string &sTimeStamp,
                     const std::string &sNonce, std::string &sResult);
};

} // namespace Tencent
