#ifdef HAVE_NFT_SUPPORT

#include "erc721_plugin.h"
#include "plugin_utils.h"
#include "eth_plugin_internal.h"

static void handle_approve(ethPluginProvideParameter_t *msg, erc721_context_t *context) {
    switch (context->next_param) {
        case OPERATOR:
            copy_address(context->address, msg->parameter, sizeof(context->address));
            context->next_param = TOKEN_ID;
            break;
        case TOKEN_ID:
            copy_parameter(context->tokenId, msg->parameter, sizeof(context->tokenId));
            context->next_param = NONE;
            break;
        default:
            PRINTF("Unhandled parameter offset\n");
            msg->result = ETH_PLUGIN_RESULT_ERROR;
            break;
    }
}

// `strict` will set msg->result to ERROR if parsing continues after `TOKEN_ID` has been parsed.
static void handle_transfer(ethPluginProvideParameter_t *msg,
                            erc721_context_t *context,
                            bool strict) {
    switch (context->next_param) {
        case FROM:
            context->next_param = TO;
            break;
        case TO:
            copy_address(context->address, msg->parameter, sizeof(context->address));
            context->next_param = TOKEN_ID;
            break;
        case TOKEN_ID:
            copy_parameter(context->tokenId, msg->parameter, sizeof(context->tokenId));
            context->next_param = NONE;
            break;
        default:
            if (strict) {
                PRINTF("Param %d not supported\n", context->next_param);
                msg->result = ETH_PLUGIN_RESULT_ERROR;
            }
            break;
    }
}

static void handle_approval_for_all(ethPluginProvideParameter_t *msg, erc721_context_t *context) {
    switch (context->next_param) {
        case OPERATOR:
            context->next_param = APPROVED;
            copy_address(context->address, msg->parameter, sizeof(context->address));
            break;
        case APPROVED:
            context->next_param = NONE;
            context->approved = msg->parameter[PARAMETER_LENGTH - 1];
            break;
        default:
            PRINTF("Param %d not supported\n", context->next_param);
            msg->result = ETH_PLUGIN_RESULT_ERROR;
            break;
    }
}

void handle_provide_parameter_721(void *parameters) {
    ethPluginProvideParameter_t *msg = (ethPluginProvideParameter_t *) parameters;
    erc721_context_t *context = (erc721_context_t *) msg->pluginContext;

    PRINTF("erc721 plugin provide parameter %d %.*H\n",
           msg->parameterOffset,
           PARAMETER_LENGTH,
           msg->parameter);

    msg->result = ETH_PLUGIN_RESULT_SUCCESSFUL;
    switch (context->selectorIndex) {
        case APPROVE:
            handle_approve(msg, context);
            break;
        case SAFE_TRANSFER:
        case TRANSFER:
            handle_transfer(msg, context, true);
            break;
        case SAFE_TRANSFER_DATA:
            // Set `strict` to `false` because additional data might be present.
            handle_transfer(msg, context, false);
            break;
        case SET_APPROVAL_FOR_ALL:
            handle_approval_for_all(msg, context);
            break;
        default:
            PRINTF("Selector index %d not supported\n", context->selectorIndex);
            msg->result = ETH_PLUGIN_RESULT_ERROR;
            break;
    }
}

#endif  // HAVE_NFT_SUPPORT
