#include "connectors/auth_http_adapter.h"

#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

static const uint8 k_secret[] =
    "0123456789abcdef0123456789abcdef";
static const char k_secret_hex[] =
    "30313233343536373839616263646566"
    "30313233343536373839616263646566";

static Seobeo_Request_Entry *request_with(
    Dowa_Arena *arena, const char *cookie, const char *origin,
    const char *csrf)
{
  Seobeo_Request_Entry *request = NULL;
  Dowa_HashMap_Push_Arena(request, "Host", "localhost:6981", arena);
  if (cookie)
    Dowa_HashMap_Push_Arena(request, "Cookie", (char *)cookie, arena);
  if (origin)
    Dowa_HashMap_Push_Arena(request, "Origin", (char *)origin, arena);
  if (csrf)
    Dowa_HashMap_Push_Arena(
        request, "X-CSRF-Token", (char *)csrf, arena);
  return request;
}

int main(void)
{
  char database[256];
  snprintf(
      database, sizeof(database), "connector_auth_%ld_%lld.db",
      (long)getpid(), (long long)time(NULL));
  unlink(database);
  Auth_Store *store = Auth_Store_Create(database);
  assert(store);
  char password_hash[AUTH_CRYPTO_PASSWORD_HASH_ENCODED_SIZE];
  assert(Auth_Crypto_Password_Hash(
      "test-password", password_hash, sizeof(password_hash)) ==
      AUTH_CRYPTO_OK);
  char user_id[37];
  assert(Auth_Store_Create_User(
      store, "connectoruser", password_hash, "member", FALSE, user_id) ==
      AUTH_STORE_OK);
  char token[AUTH_CRYPTO_TOKEN_SIZE];
  char token_digest[AUTH_CRYPTO_TOKEN_DIGEST_SIZE];
  char csrf[AUTH_CRYPTO_TOKEN_SIZE];
  char csrf_digest[AUTH_CRYPTO_TOKEN_DIGEST_SIZE];
  assert(Auth_Crypto_Token_Generate(token, sizeof(token)) == AUTH_CRYPTO_OK);
  assert(Auth_Crypto_Token_Digest(
      token, token_digest, sizeof(token_digest)) == AUTH_CRYPTO_OK);
  assert(Auth_HTTP_Derive_CSRF(
      k_secret, sizeof(k_secret) - 1, token_digest, csrf, sizeof(csrf)));
  assert(Auth_Crypto_Token_Digest(
      csrf, csrf_digest, sizeof(csrf_digest)) == AUTH_CRYPTO_OK);
  Auth_Session_Record session;
  int64 now = (int64)time(NULL);
  assert(Auth_Store_Create_Session(
      store, user_id, token_digest, csrf_digest, 3600, 86400, now,
      &session) == AUTH_STORE_OK);
  Auth_Store_Destroy(store);

  Connector_Auth_HTTP_Context context;
  assert(Connector_Auth_HTTP_Init(
      &context, database, k_secret_hex, 3600));
  Connector_Auth_Adapter adapter =
      Connector_Auth_HTTP_Create_Adapter(&context);
  Dowa_Arena *arena = Dowa_Arena_Create(32 * 1024);
  char cookie[AUTH_CRYPTO_TOKEN_SIZE + 32];
  snprintf(cookie, sizeof(cookie), "mjj_session=%s", token);

  Seobeo_Request_Entry *read_request =
      request_with(arena, cookie, NULL, NULL);
  const char *resolved = adapter.resolve_user(
      read_request, FALSE, arena, adapter.context);
  assert(resolved && !strcmp(resolved, user_id));
  Connector_Auth_Session connector_session;
  assert(adapter.resolve_session(
      read_request, &connector_session, adapter.context));
  assert(!strcmp(connector_session.user_id, user_id));
  assert(!strcmp(connector_session.username, "connectoruser"));
  assert(!strcmp(connector_session.role, "member"));
  assert(!strcmp(connector_session.csrf_token, csrf));
  assert(!adapter.resolve_user(
      read_request, TRUE, arena, adapter.context));

  Seobeo_Request_Entry *write_request = request_with(
      arena, cookie, "http://localhost:6981", csrf);
  resolved = adapter.resolve_user(
      write_request, TRUE, arena, adapter.context);
  assert(resolved && !strcmp(resolved, user_id));

  Seobeo_Request_Entry *wrong_origin = request_with(
      arena, cookie, "https://evil.example", csrf);
  assert(!adapter.resolve_user(
      wrong_origin, TRUE, arena, adapter.context));
  Seobeo_Request_Entry *wrong_cookie = request_with(
      arena, "mjj_session=invalid", NULL, NULL);
  assert(!adapter.resolve_user(
      wrong_cookie, FALSE, arena, adapter.context));
  assert(!adapter.resolve_session(
      wrong_cookie, &connector_session, adapter.context));

  Dowa_Arena_Free(arena);
  Connector_Auth_HTTP_Destroy(&context);
  unlink(database);
  puts("auth_http_adapter_test: ok");
  return 0;
}
