#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#if defined(__GNUC__)
#define ACTRAIL_PATCHABLE_ENTRY __attribute__((patchable_function_entry(32, 0)))
#else
#define ACTRAIL_PATCHABLE_ENTRY
#endif

static const char *fallback_reply(void) {
  const char *reply = getenv("ACTRAIL_DYNAMIC_TLS_REPLY");
  return reply == NULL ? "" : reply;
}

ACTRAIL_PATCHABLE_ENTRY int SSL_write(void *ssl, const void *buffer, int length) {
  (void)ssl;
  (void)buffer;
  return length;
}

ACTRAIL_PATCHABLE_ENTRY int SSL_write_ex(void *ssl, const void *buffer, size_t length, size_t *written) {
  (void)ssl;
  (void)buffer;
  if (written != NULL) {
    *written = length;
  }
  return 1;
}

ACTRAIL_PATCHABLE_ENTRY int SSL_write_ex2(void *ssl, const void *buffer, size_t length, uint64_t flags,
                                          size_t *written) {
  (void)ssl;
  (void)buffer;
  (void)flags;
  if (written != NULL) {
    *written = length;
  }
  return 1;
}

ACTRAIL_PATCHABLE_ENTRY int SSL_do_handshake(void *ssl) {
  (void)ssl;
  return 1;
}

ACTRAIL_PATCHABLE_ENTRY int SSL_read(void *ssl, void *buffer, int length) {
  (void)ssl;
  const char *reply = fallback_reply();
  size_t reply_len = strlen(reply);
  if (buffer == NULL || length <= 0 || reply_len == 0) {
    return 0;
  }
  size_t limit = (size_t)length;
  size_t copied = reply_len < limit ? reply_len : limit;
  memcpy(buffer, reply, copied);
  return (int)copied;
}

ACTRAIL_PATCHABLE_ENTRY int SSL_read_ex(void *ssl, void *buffer, size_t length, size_t *read_bytes) {
  (void)ssl;
  const char *reply = fallback_reply();
  size_t reply_len = strlen(reply);
  if (read_bytes != NULL) {
    *read_bytes = 0;
  }
  if (buffer == NULL || length == 0 || reply_len == 0) {
    return 0;
  }
  size_t copied = reply_len < length ? reply_len : length;
  memcpy(buffer, reply, copied);
  if (read_bytes != NULL) {
    *read_bytes = copied;
  }
  return 1;
}