# frozen_string_literal: true

require "ffi"

module QuicProQuo
  # Low-level FFI bindings to libquicproquo_ffi.
  #
  # The library is located via:
  # 1. QPQ_LIB_PATH environment variable
  # 2. Common cargo build output paths
  # 3. System library path
  module FFIBindings
    extend FFI::Library

    # Status codes (mirrors crates/quicproquo-ffi/src/lib.rs).
    QPQ_OK            = 0
    QPQ_ERROR         = 1
    QPQ_AUTH_FAILED   = 2
    QPQ_TIMEOUT       = 3
    QPQ_NOT_CONNECTED = 4

    # Locate and load the shared library.
    LIB_SEARCH_PATHS = [
      ENV.fetch("QPQ_LIB_PATH", nil),
      File.expand_path("../../../../target/release/libquicproquo_ffi.so", __dir__),
      File.expand_path("../../../../target/debug/libquicproquo_ffi.so", __dir__),
      File.expand_path("../../../../target/release/libquicproquo_ffi.dylib", __dir__),
      File.expand_path("../../../../target/debug/libquicproquo_ffi.dylib", __dir__),
      "quicproquo_ffi",
    ].compact.freeze

    lib_path = LIB_SEARCH_PATHS.find { |p| File.exist?(p) } || "quicproquo_ffi"
    ffi_lib lib_path

    # QpqHandle* qpq_connect(const char*, const char*, const char*)
    attach_function :qpq_connect, %i[string string string], :pointer

    # int qpq_login(QpqHandle*, const char*, const char*)
    attach_function :qpq_login, %i[pointer string string], :int

    # int qpq_send(QpqHandle*, const char*, :pointer, size_t)
    attach_function :qpq_send, %i[pointer string pointer size_t], :int

    # int qpq_receive(QpqHandle*, uint32, :pointer)
    attach_function :qpq_receive, %i[pointer uint32 pointer], :int

    # void qpq_disconnect(QpqHandle*)
    attach_function :qpq_disconnect, [:pointer], :void

    # const char* qpq_last_error(const QpqHandle*)
    attach_function :qpq_last_error, [:pointer], :string

    # void qpq_free_string(char*)
    attach_function :qpq_free_string, [:pointer], :void
  end
end
