#include "Send_APDU.h"
#include "dk_utils.h"
#include "dk_cmd_get_response.h"

DK_Result process_send_apdu(tl_dk_ctx_t *ctx, tz_dk_send_apdu_payload_t *sendmsg, tz_dk_send_apdu_payload_t *respmsg)
{
    DK_Result res;

    uint8_t data[CPDU_MAX_SIZE] = {0};
    uint8_t response[RPDU_MAX_SIZE] = {0};
    // uint8_t full_response[MAX_RESPONSE_SIZE] = {0};

    size_t data_len = CPDU_MAX_SIZE;
    size_t response_len = RPDU_MAX_SIZE;
    // size_t full_response = MAX_RESPONSE_SIZE;

    uint8_t rdata[MAX_RAPDU_DATA_SIZE];

    secEse_7816_rpdu_t rpdu;
    rpdu.pdata = rdata;

    if (!ctx->channel.is_open) {
        DK_LOG_ERR("process_send_apdu: channel is closed");
        respmsg->payload.resp.return_code = res =  DK_ERROR_BAD_STATE;
        goto catch_error;
    }

    if (ctx->scp_ctx.session_state != SESSION_OPEN) {
        DK_LOG_ERR("process_send_apdu: session is not open");
        respmsg->payload.resp.return_code = res =  DK_ERROR_BAD_STATE;
        goto catch_error;
    }

    if (sendmsg->payload.cmd.data_len > CPDU_MAX_DATA_SIZE) {
        DK_LOG_ERR("process_send_apdu: command size exceeds max size");
        respmsg->payload.resp.return_code = res =  DK_ERROR_BAD_PARAM;
        goto catch_error;
    }

    dk_memcpy(data, sendmsg->payload.cmd.data, sendmsg->payload.cmd.data_len);
    data_len = sendmsg->payload.cmd.data_len;

    // scp_dump_context(&ctx->scp_ctx);
    // printf(TAG"command[%d]: ", data_len);
    // print_array(data, data_len);

    res = scp_wrap_command(&ctx->scp_ctx, data, data_len, data, &data_len);
    if (res) {
        DK_LOG_ERR("process_send_apdu: bad wrapping");
        respmsg->payload.resp.return_code = res;
        goto catch_error;
    }


    res = transmit(data, data_len, &rpdu, &ctx->channel);
    if (res) {
        DK_LOG_ERR("process_send_apdu: error on transmit");
        respmsg->payload.resp.return_code = res;
        goto catch_error;
    }

    // rpdu_dump(&rpdu);

    // TODO: response apdu can be much bigger than 256 bytes, need to 
    // call handle_fragmented_response in this case, but for now SCP
    // only supports unwrapping RPDUs that are up to 258 bytes long

    // res = rpdu_to_barray(response, &response_len, &rpdu);
    // if (res) {
    //     DK_LOG_ERR("process_send_apdu: error on fragmented response");
    //     respmsg->payload.resp.return_code = res;
    //     goto catch_error;
    // }

    res = handle_fragmented_response(&rpdu, response, &response_len, &ctx->channel);
    if (res) {
        DK_LOG_ERR("process_send_apdu: bad fragmented response - 0x%x", res);
        respmsg->payload.resp.return_code = res;
        goto catch_error;
    }

    // printf(TAG"response[%d]: ", response_len);
    // print_array(response, response_len);

    res = scp_unwrap_response(&ctx->scp_ctx, response, response_len, response, &response_len);
    if (res) {
        DK_LOG_ERR("process_send_apdu: bad unwrap");
        respmsg->payload.resp.return_code = res;
        goto catch_error;
    }

    ctx->scp_ctx.encryption_counter++;

    if (response_len == 0 || response_len > MAX_FULL_RESPONSE_SIZE) {
        DK_LOG_ERR("process_send_apdu: response size exceeds max response size");
        respmsg->payload.resp.return_code = res = DK_ERROR_GENERIC;
        goto catch_error;
    }

    dk_memcpy(respmsg->payload.resp.data, response, response_len);
    respmsg->payload.resp.data_len = response_len;
    respmsg->payload.resp.return_code = res = DK_SUCCESS;

catch_error:
    return res;
}
