#include "pa_tz_api.h"
#include "config.h"
#include "driver_log.h"
#include "entry.h"

#include <DrApi/DrApi.h>

#include <tee_internal_api.h>
#include <tees_sys.h>

extern threadid_t g_current_client_thread_id;

/**
 * @brief Return task id of current client
 * @return taskid
 */
taskid_t GetCurrentClientTaskId(void) {
  // TODO(d.pavlyuk): g_current_client_thread_id usage should be limited by IPC-thread only
  return  THREADID_TO_TASKID(g_current_client_thread_id);
}

TEE_Result PlatformGetCallerUuid(TEE_UUID *uuid) {
  if (!uuid) {
    LOG_E("Invalid argument.\n");
    return TEE_ERROR_BAD_PARAMETERS;
  }

  // TODO(d.pavlyuk): g_current_client_thread_id usage should be limited by IPC-thread only
  size_t uuid_size = sizeof(*uuid);
  drApiResult_t result = drApiGetClientProperty(g_current_client_thread_id,
                                                PROPERTY_UUID, uuid, &uuid_size);
  if (result != DRAPI_OK || uuid_size != sizeof(*uuid)) {
    LOG_E("Failed drApiGetClientProperty.\n");
    LOG_D("result: %d, uuid_size = %d, sizeof(TEE_UUID) = %d\n",
          result, uuid_size, sizeof(*uuid));
    return TEE_ERROR_GENERIC;
  }

  return TEE_SUCCESS;
}

TEE_Result TA_CreateEntryPoint(void) {
  return TEE_SUCCESS;
}

void TA_DestroyEntryPoint(void) {
}

TEE_Result TA_OpenSessionEntryPoint(uint32_t paramTypes, TEE_Param params[4],
                                    void **sessionContext) {
  (void)sessionContext;

  if (TEE_PARAM_TYPE_GET(paramTypes, 0) != TEE_PARAM_TYPE_MEMREF_INOUT) {
    LOG_E("Type of input parameters have other type\n");
    return TEE_ERROR_BAD_PARAMETERS;
  }

  TEE_Result result = Entry();
  if (result != TEE_SUCCESS) {
    LOG_E("Failed Entry.\n");
    LOG_D("Received result: 0x%x.\n", result);
    return result;
  }

  return TEE_SUCCESS;
}

void TA_CloseSessionEntryPoint(void *sessionContext) {
  (void)sessionContext;
}

TEE_Result TA_InvokeCommandEntryPoint(void *sessionContext, uint32_t commandID,
                                      uint32_t paramTypes, TEE_Param params[4]) {
  (void)sessionContext;

  if (TEE_PARAM_TYPE_GET(paramTypes, 0) != TEE_PARAM_TYPE_MEMREF_INOUT ||
      TEE_PARAM_TYPE_GET(paramTypes, 1) != TEE_PARAM_TYPE_VALUE_OUTPUT) {
    LOG_E("Type of input parameters have other type\n");
    return TEE_ERROR_BAD_PARAMETERS;
  }

  TEE_Result status = TEES_HandleDriverCommand(commandID,
      (void *)params[0].memref.buffer, params[0].memref.size,
      (void *)params[0].memref.buffer, &(params[0].memref.size));
  if (status != TEE_SUCCESS) {
    LOG_E("TEES_HandleDriverCommand return error.\n");
    LOG_D("Received result: 0x%x.\n", status);
  }

  params[1].value.a = status;

  return TEE_SUCCESS;
}
