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

#include "../nostr_core/nostr_platform.h"

#if defined(ARDUINO)
#include <Arduino.h>
#endif

#if defined(__has_include)
#  if __has_include("pico/rand.h")
#    include "pico/rand.h"
#    define NOSTR_HAVE_PICO_RAND 1
#  endif
#  if __has_include("hardware/adc.h")
#    include "hardware/adc.h"
#    define NOSTR_HAVE_PICO_ADC 1
#  endif
#endif

static uint32_t xorshift32(uint32_t *state) {
    uint32_t x = *state ? *state : 0xA5A5A5A5u;
    x ^= x << 13;
    x ^= x >> 17;
    x ^= x << 5;
    *state = x;
    return x;
}

int nostr_platform_random(unsigned char *buf, size_t len) {
    if (!buf) {
        return -1;
    }

    size_t i = 0;

#if defined(NOSTR_HAVE_PICO_RAND)
    while (i + 4 <= len) {
        uint32_t r = get_rand_32();
        memcpy(buf + i, &r, 4);
        i += 4;
    }
    if (i < len) {
        uint32_t r = get_rand_32();
        memcpy(buf + i, &r, len - i);
    }
    return 0;
#else
    uint32_t seed = 0x13579BDFu;

#if defined(ARDUINO)
    seed ^= (uint32_t)micros();
    seed ^= ((uint32_t)millis() << 16);
    seed ^= (uint32_t)(uintptr_t)&seed;
#endif

#if defined(NOSTR_HAVE_PICO_ADC)
    adc_init();
    adc_set_temp_sensor_enabled(true);
    adc_select_input(4);
    for (int k = 0; k < 16; ++k) {
        seed ^= ((uint32_t)adc_read() << ((k & 3) * 8));
    }
#endif

    while (i < len) {
        uint32_t r = xorshift32(&seed);
#if defined(ARDUINO)
        r ^= (uint32_t)micros();
#endif
        size_t take = (len - i >= 4) ? 4 : (len - i);
        memcpy(buf + i, &r, take);
        i += take;
    }

    return 0;
#endif
}
