#pragma once

#include <ioringapi.h>
#include <ntioring_x.h>
// #include "ioringapi.c"
#include <winerror.h>

// Initialize I/O Ring
HIORING io_ring_init(void) {

  // if (!io_ring_load_functions()) {
  //   printf("[I/O Ring] Failed to load functions\n");
  //   return NULL;
  // }

  IORING_CAPABILITIES caps;
  ZeroMemory(&caps, sizeof(caps));

  HRESULT hr = QueryIoRingCapabilities(&caps);
  if (FAILED(hr)) {
    printf("[I/O Ring] QueryIoRingCapabilities failed: 0x%08lx\n", hr);
    return NULL;
  }

  // printf("[I/O Ring] MaxVersion=%d, MaxSubmission=%u, MaxCompletion=%u\n",
  //        (int)caps.MaxVersion, caps.MaxSubmissionQueueSize,
  // caps.MaxCompletionQueueSize);

  if (caps.MaxVersion < IORING_VERSION_1) {
    printf("[I/O Ring] Version too old\n");
    return NULL;
  }

  IORING_CREATE_FLAGS flags = {0};
  HIORING ring = NULL;

  // hr = CreateIoRing(IORING_VERSION_1, flags, 256, 512, &ring);
  hr = CreateIoRing(caps.MaxVersion, flags, 256, 512, &ring);
  if (FAILED(hr)) {
    printf("[I/O Ring] CreateIoRing failed: 0x%08lx\n", hr);
    return NULL;
  }

  // printf("[I/O Ring] Created successfully\n");

  // Check if read operation is supported

  // HRESULT io_ring_support = IsIoRingOpSupported(ring, IORING_OP_READ);
  // if (io_ring_support == S_FALSE) {
  //   printf("[I/O Ring] Not supported, %ld /n", io_ring_support);
  // }

  // Get ring info
  IORING_INFO info;
  ZeroMemory(&info, sizeof(info));
  GetIoRingInfo(ring, &info);
  // printf("[I/O Ring] Submission: %u, Completion: %u\n",
  // info.SubmissionQueueSize, info.CompletionQueueSize);

  return ring;
}

void io_ring_cleanup(HIORING ring) {
  if (ring) {
    CloseIoRing(ring);
    // printf("[I/O Ring] Closed\n");
  }
}

// Read file using I/O Ring
int io_ring_read_file(HIORING ring, HANDLE hFile, void *buffer, DWORD size,
                      UINT64 offset) {

  IORING_HANDLE_REF file_ref = IoRingHandleRefFromHandle(hFile);
  IORING_BUFFER_REF buf_ref = IoRingBufferRefFromPointer(buffer);

  HRESULT hr = BuildIoRingReadFile(ring, file_ref, buf_ref, size, offset,
                                   (UINT_PTR)buffer, IOSQE_FLAGS_NONE);

  if (FAILED(hr))
    return -1;

  UINT32 submitted = 0;
  hr = SubmitIoRing(ring, 1, INFINITE, &submitted);
  if (FAILED(hr) || submitted == 0)
    return -1;

  for (;;) {
    IORING_CQE cqe;
    hr = PopIoRingCompletion(ring, &cqe);

    if (FAILED(hr))
      continue;

    if (cqe.UserData != (UINT_PTR)buffer)
      continue;

    if (FAILED(cqe.ResultCode))
      return -1;

    return (int)cqe.Information;
  }
}

// Test function
void test_io_ring(void) {
  printf("\n=== Testing I/O Ring ===\n");

  HIORING ring = io_ring_init();
  if (!ring) {
    printf("I/O Ring not available\n");
    return;
  }

  // Create test file
  HANDLE hFile = CreateFileA("test.txt", GENERIC_READ | GENERIC_WRITE, 0, NULL,
                             CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  if (hFile != INVALID_HANDLE_VALUE) {
    char test_data[] =
        "Hello, I/O Ring! This is a test of the Windows I/O Ring API.";
    DWORD written;
    WriteFile(hFile, test_data, sizeof(test_data), &written, NULL);
    CloseHandle(hFile);
  }

  // Read using I/O Ring
  hFile = CreateFileA("test.txt", GENERIC_READ, FILE_SHARE_READ, NULL,
                      OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
  if (hFile != INVALID_HANDLE_VALUE) {
    char buffer[512] = {0};
    int bytes = io_ring_read_file(ring, hFile, buffer, sizeof(buffer), 0);
    if (bytes > 0) {
      printf("Read %d bytes: %s\n", bytes, buffer);
    } else {
      printf("Failed to read file\n");
    }
    CloseHandle(hFile);
  } else {
    printf("Failed to open test file\n");
  }

  // Cleanup
  DeleteFileA("test.txt");
  io_ring_cleanup(ring);

  printf("=== Test complete ===\n\n");
}
