#ifndef __IFAA_TA_COMMON_H__
#define __IFAA_TA_COMMON_H__

#include <limits.h>

#include "ifaa_tlv_common.h"
#include "ifaa_tee_common.h"
#include "ifaa_ta_commandId.h"

/**
 * Get the last identified ID
 * @param buf_id: Get the last identified ID(out parameter)
 * @param id_len: buf_id lenth(in+out parameter)
 *
 */
typedef IFAA_Result (*IFAA_LastIdentifiedResultGetter)(uint8_t *buf_id, uint32_t *id_len);

/**
 * Get Authenticator version
 * @param buf_version: get Authenticator version(out parameter)
 * @param version_len: buf_version's length(in+out parameter)
 */
typedef IFAA_Result (*IFAA_AuthenticatorVersionGetter)(uint32_t *version);

/**
 * Get Enroll id list
 * @param buf_id_list:
 *      +-------------------------------------+
 *      |id1_len | id_1 | id2_len | id_2 | ...|
 *      +-4bytes----------4bytes--------------+
 * @param id_list_len: buffer length(in+out parameter)
 */
typedef IFAA_Result (*IFAA_IdListGetter)(uint8_t *buf_id_list, uint32_t *id_list_len);


typedef enum {
    IFAA_NO = 0,
    IFAA_YES
} IFAABoolean;

/**
 * id comparison operator
 * @param buf_l: wair for comparison buffer
 * @param buf_r: Was compared buffer
 */
typedef IFAABoolean (*IFAA_IdEquator)(const uint8_t *buf_l, const uint8_t *buf_r, uint32_t buf_len);

/**
 * command list
 */
typedef enum {
    IFAA_TA_CMD_GET_DEVICE_ID = 1 << 0,
    IFAA_TA_CMD_REGISTER = 1 << 1,
    IFAA_TA_CMD_AUTHENTICATE = 1 << 2,
    IFAA_TA_CMD_DEREGISTER = 1 << 3,
    IFAA_TA_CMD_QUERY_STATUS = 1 << 4, //query the enlightened state
    IFAA_TA_CMD_GEN_ASYMMETRIC_KEY = 1 << 5,
    IFAA_TA_CMD_GET_PROTOCOL_VERSION = 1 << 6,

#ifndef IFBIO_RELEASE //Only for test command
    IFAA_TA_CMD_GET_CERT_ALG_ENCODE = 1 << 7, //get the supported certificate code of TA
    /////file operation
    IFAA_TA_CMD_READ_FILE,
    IFAA_TA_CMD_WRITE_FILE,
    IFAA_TA_CMD_DELETE_FILE,

    /////Sensor operation
    IFAA_INTERNAL_GET_LAST_IDENTIFIED_RESULT,   //get last identified ID
    IFAA_INTERNAL_GET_AUTHENTICATOR_VERSION,
    IFAA_INTERNAL_GET_ID_LIST,
    IFAA_INTERNAL_BIO_ID_COMPARE,

    /////Encryption and decryption operation
    IFAA_INTERNAL_SHA256,
    IFAA_INTERNAL_SIGN,
    IFAA_INTERNAL_VERIFY,                       //verify signature
    IFAA_INTERNAL_KEY_GENERATE,                 //Generate public/private key
    IFAA_INTERNAL_HMAC_SHA1,
    IFAA_INTERNAL_AUTHENTICATOR_SIGN,           //authenticator sign(we can not implement now)
    IFAA_INTERNAL_AUTHENTICATOR_VERIFY,         //authenticator verify signature
    IFAA_INTERNAL_ECC_KEY_GENERATE,				//generate ECC keypair
    IFAA_INTERNAL_ECC_SIGN,                     //ECC sign
    IFAA_INTERNAL_ECC_VERIFY,                   //ECC sign verify

    IFAA_TA_CMD_GET_SEC_DEVICE_ID = 1 << 8, //get the deviec id that was signatured
#endif


    IFAA_TA_CMD_GET_SKPM_INJECT_STATE = 1 << 9,
    IFAA_TA_CMD_PROVISIONING_KEY_HANDLE,
#ifndef IFBIO_RELEASE //Clear sfs feature maybe opened in the future
    IFAA_TA_CMD_CLEAR_SFS_FILE_LIST = IFAA_TA_CMD_GET_SKPM_INJECT_STATE + 2,
#endif
    IFAA_TA_CMD_GET_ID_LIST = IFAA_TA_CMD_GET_SKPM_INJECT_STATE + 10,
    IFAA_TA_CMD_SET_ID_LIST,

} ifaa_ta_cmd;

typedef struct ifaa_ta_cmd_pair{
    ifaa_ta_cmd cmd_id;
    const char *cmd_string;
} ifaa_ta_cmd_pair_t;

typedef enum {
    IFAA_BIO_FINGERPRINT = 1 << 0,
    IFAA_BIO_IRIS = 1 << 1,
    IFAA_BIO_FACE = 1 << 2,

    IFAA_BIO_OTHER = 1 << 8,
    //more
} IFAA_BioType;


typedef enum {
    IFAA_ENTRY_LAST_IDENTIFIED_RESULT_GETTER = 0x01,
    IFAA_ENTRY_AUTHENTICATOR_VERSION_GETTER,
    IFAA_ENTRY_ID_LIST_GETTER,
    IFAA_ENTRY_EQUATOR
    //more
} IFAA_TaEntry;

/**
 * TA command entrance
 * param buf_in: input buffer
 * format：
 *     +------------------------------------------------------------+
 *     | version | sig_len | sig | pkg_len | pkg |  cmd  | params.. |
 *     +-4bytes-----4bytes-----------4bytes-------4bytes------------+
 * param in_len: input buffer length
 *
 * param_buf_out: output buffer(out parameter)
 * format：
 *     +----------------------------------+
 *     | TEE_Result | total_len | value.. |
 *     +--4bytes-------4bytes-------------+
 * param out_len: output buffer length(in + out parameter)
 */
IFAA_Result IFAA_TaInvokeCmd(uint8_t *buf_in, uint32_t in_len, uint8_t *buf_out, uint32_t *out_len);


/**
 * add Entry
 * @param bioType: biometric type
 * @param entry:
 * @param func: function entry address
 */
IFAA_Result IFAA_TaAddEntry(IFAA_BioType bioType, IFAA_TaEntry entry, void *func);

/**
 *Get Entry
 * @param bioType:  biometric type
 * @param entry:
 * @param func:     function entry address(out parameter)
 */
IFAA_Result IFAA_TaGetEntry(IFAA_BioType bioType, IFAA_TaEntry entry, void **func);


IFAA_Result
IFAA_Sha256(const uint8_t *msg, uint32_t msg_len, uint8_t *digest, uint32_t *digest_len);

typedef struct {
    uint8_t *buf;
    uint32_t len;
} vlb_t;

#define IFAA_INITIALISE_VLB(vlb) \
    do {                         \
        vlb.buf = NULL;          \
        vlb.len = 0;             \
    } while(0)

typedef struct {
    vlb_t n;
    vlb_t d;
    vlb_t e;
} IFAA_RsaKey;

typedef struct {
    vlb_t p;   //private key
    vlb_t x;   //public key x
    vlb_t y;   //public key y
} IFAA_EccKey;

typedef struct {
    IFAA_AsymmetricKeyType type;
    union {
       IFAA_RsaKey rsa;
       IFAA_EccKey ecc;
    } asym_key;
} IFAA_AsymKeyAndType;

///**
// * IFAA自定义证书格式
// * +----------------------------------------------------+
// * | n_len |  n   | e_len |   e   | sig_len | signature |
// * +-4bytes--------4bytes------------4bytes-------------+
// */
//typedef struct {
//    /**
//     * 公钥格式
//     * +-----------------------+
//     * | n_len | n | e_len | e |
//     * +-4bytes-----4bytes-----+
//     */
//    vlb_t pub_key;      //公钥buffer
//    vlb_t sig;          //签名
//} IFAA_Certificate;


/**
 * 证书统一编码格式 tag-union
 * +---------------------------------------+
 * | cert_enc_alg | content of certificate |
 * +----4 bytes----------------------------+
 */
typedef struct x509 x509; //forward declaration

typedef struct {
    IFAA_CertEncodeAlgorithm cert_enc_alg; //certificate type

    union {
        //////////////////////////////////////////////////
        // IFAA custom certificate serialization format
        // +---------------------------------------------+
        // | n_len | n | e_len | e | sig_len | signature |
        // +-4bytes------4bytes-------4bytes-------------+
        //////////////////////////////////////////////////
        struct {
            /**
             * public key serialization format
             * +-----------------------+
             * | n_len | n | e_len | e |
             * +-----------------------+
             */
            struct {
                vlb_t n;
                vlb_t e;
            } pub_key;
            vlb_t sig;
        } ifaa_cert;

        //////////////////////////////////////////////////
        // X509 standard certificate
        //////////////////////////////////////////////////
        struct {
            vlb_t x509;
            //x509 *certificate(DER Format)
        } x509_cert;

        //more others...
    } body;
} IFAA_Certificate;

IFAA_Result IFAA_EccKeyGenerate(IFAA_EccKey* key);

IFAA_Result IFAA_EccVerifyDigest(const IFAA_EccKey* key, const uint8_t* digest, uint32_t digest_len, const uint8_t* sig, uint32_t sig_len);

IFAA_Result IFAA_EccSignDigest(const IFAA_EccKey* key,const uint8_t* digest, uint32_t digest_len,uint8_t* sig, uint32_t* sig_len);

/**
 * sign
 * @param key:          pri key
 * @param digest:       digest
 * @param digest_len:   diget len
 * @param sig:          signature(out)
 * @param sig_len:      signature length(in+out)
 */
IFAA_Result IFAA_RsaSignDigest(const IFAA_RsaKey* key,
                               const uint8_t* digest, uint32_t digest_len,
                               uint8_t* sig, uint32_t* sig_len);

/**
 * verifySign
 * @param key:          public key
 * @param digest:       digest
 * @param digest_len:   digest length
 * @param sig:          signature
 * @param sig_len:      signature length
 */
IFAA_Result IFAA_RsaVerifyDigest(const IFAA_RsaKey* key,
                                 const uint8_t* digest, uint32_t digest_len,
                                 const uint8_t* sig, uint32_t sig_len);


typedef enum {
    RSA_BITS_2048,
    RSA_BITS_4096,
} IFAA_RsaBit;


/**
 * generate RSA keypair
 * @param bits: key length
 * @param key:  generated key(out)
 */
IFAA_Result IFAA_RsaKeyGenerate(IFAA_RsaBit bits, IFAA_RsaKey *key);


/**
 * HMAC_SHA1
 */
IFAA_Result IFAA_HmacSha1(const uint8_t *msg, uint32_t msg_len,
                          const uint8_t *key, uint32_t key_len,
                          uint8_t *mac);

/**
 * Format:
 * +----------------------------------------------------------------------+
 * | device vendor | chip vendor | TEE vendor | sensor vendor | device id |
 * +----2 bytes--------2 bytes------2 bytes--------2 bytes-------40 bytes-+
 *
 */
IFAA_Result IFAA_GetDeviceId(uint8_t *device_id, uint32_t *device_id_len);


IFAA_Result IFAA_GetProtocolVersion(uint8_t *version, uint32_t *version_len);


IFAA_Result IFAA_GetOptionalCertEncodeAlg(uint8_t *algs, uint32_t *algs_len);


/**
 * certificate verify
 * @param digest:
 * @param digest_len:
 * @param signature:
 * @param sig_len:   
 * @param cert_chain:
 * @param cert_count:
 */
IFAA_Result IFAA_AuthenticatorVerifyDigest(const uint8_t *digest, uint32_t digest_len,
                                           const uint8_t *signature, uint32_t sig_len,
                                           const IFAA_Certificate *cert_chain, uint32_t cert_count);

/**
 * sign by certificate
 * @param digest:
 * @param digest_len:
 * @param signature:
 * @param sig_len:
 */
IFAA_Result IFAA_AuthenticatorSignDigest(const uint8_t* digest, uint32_t digest_len,
                                         uint8_t* signature, uint32_t* sig_len);

//IFAA_Result IFAA_AuthenticatorSignDigest(const uint8_t* digest, uint32_t digest_len,
//                                         const uint8_t* cert_chain, uint32_t cert_chain_len,
//                                         uint8_t* signature, uint32_t* sig_len);


IFAA_Result IFAA_WriteFile(const char *path, uint32_t path_len, const uint8_t *data, uint32_t len);


IFAA_Result IFAA_ReadFile(const char *path, uint32_t path_len, uint8_t *data, uint32_t *len);


IFAA_Result IFAA_DeleteFile(const char *path, uint32_t path_len);

IFAA_Result IFAA_GetFpLastIdentifiedResult(uint8_t *buf_id, uint32_t *id_len);

IFAA_Result IFAA_GetFpEnrolledIdList(uint8_t *buf_id_list, uint32_t *id_list_len);

IFAA_Result IFAA_ClearFiles();

int copy_S_BIGINT(uint8_t *dst, uint32_t dst_len, QSEE_S_BIGINT *src, uint32_t max_len);

const char * IFAA_getCmdString(ifaa_ta_cmd);

#endif //IFAACLIENTTESTAPP_IFAA_TA_COMMON_H




