#pragma once

#include <cassert>
#include <cstring>
#include <deque>
#include <mutex>
#include <span>
#include <sys/socket.h>
#include <sys/uio.h>
#include <unistd.h>

#include "arena.hpp"
#include "connection_handler.hpp"
#include "reference.hpp"

#ifndef __has_feature
#define __has_feature(x) 0
#endif

// Forward declaration
struct Server;

/**
 * Base interface for sending messages to a connection.
 * This restricted interface is safe for use by pipeline threads,
 * containing only the append_message method needed for responses.
 * Pipeline threads should use WeakRef<MessageSender> to safely
 * send responses without accessing other connection functionality
 * that should only be used by the I/O thread.
 */
struct MessageSender {
  /**
   * @brief Append message data to connection's outgoing message queue.
   *
   * Thread-safe method that can be called from any thread, including
   * pipeline processing threads. The arena is moved into the connection
   * to maintain data lifetime until the message is sent.
   *
   * @param data_parts Span of string_view parts to send (arena-allocated)
   * @param arena Arena containing the memory for data_parts string_views
   * @param close_after_send Whether to close connection after sending
   *
   * Example usage:
   * ```cpp
   * auto response_parts = std::span{arena.allocate<std::string_view>(2), 2};
   * response_parts[0] = "HTTP/1.1 200 OK\r\n\r\n";
   * response_parts[1] = "Hello World";
   * conn.append_message(response_parts, std::move(arena));
   * ```
   */
  virtual void append_message(std::span<std::string_view> data_parts,
                              Arena arena, bool close_after_send = false) = 0;

  virtual ~MessageSender() = default;
};

/**
 * Represents a single client connection with thread-safe concurrent access.
 *
 * Connection ownership model:
 * - Server owns all connections
 * - Handlers receive Connection& references, and can keep a WeakRef to
 * Connection for async responses.
 * - Multiple pipeline threads can safely access connection concurrently
 * - I/O thread has exclusive access to socket operations
 *
 * Threading model:
 * - Single mutex protects all connection state
 * - Pipeline threads call Connection methods (append_message, etc.)
 * - I/O thread processes socket events and message queue
 * - Pipeline threads manage epoll interests via Connection methods
 * - Connection tracks closed state to prevent EBADF errors
 *
 * Arena allocator usage:
 * - Request-scoped arenas created by handlers for each request
 * - No connection-owned arena for parsing/response generation
 * - Message queue stores spans + owning arenas until I/O completion
 */
struct Connection : MessageSender {
  // No public constructor or factory method - only Server can create
  // connections

  /**
   * @brief Destroy the Connection object.
   *
   * Automatically handles cleanup of all connection resources:
   * - Calls handler's on_connection_closed() method for protocol-specific
   * cleanup
   * - Decrements the global active connection counter
   * - Closes the socket file descriptor
   * - Frees all arena-allocated memory
   *
   * @note The destructor will abort() if socket close fails, as this indicates
   * a serious system-level issue that should not be ignored.
   */
  ~Connection();

  // Handler interface - public methods that handlers can use

  /**
   * @brief Queue an atomic message to be sent to the client.
   *
   * Adds a complete message with all associated data to the connection's
   * outgoing message queue. The message will be sent asynchronously by a
   * server I/O thread using efficient vectored I/O.
   *
   * @param data_parts Span of string_views pointing to arena-allocated data
   * @param arena Arena that owns all the memory referenced by data_parts
   * @param close_after_send Whether to close connection after sending this
   * message
   *
   * @note Thread Safety: This method is thread-safe and can be called
   * concurrently from multiple pipeline threads.
   *
   * @note The memory referenced by the data_parts span, must outlive @p arena.
   * The arena will be moved and kept alive until the message is fully sent.
   *
   * Example usage:
   * ```cpp
   * Arena arena;
   * auto* parts = arena.allocate<std::string_view>(2);
   * parts[0] = build_header(arena);
   * parts[1] = build_body(arena);
   * conn.append_message({parts, 2}, std::move(arena));
   * ```
   */
  void append_message(std::span<std::string_view> data_parts, Arena arena,
                      bool close_after_send = false) override;

  /**
   * @brief Get a WeakRef to this connection for async operations.
   *
   * Returns a WeakRef that can be safely used to access this connection
   * from other threads, such as pipeline processing threads. The WeakRef
   * allows safe access even if the connection might be destroyed by the
   * time the async operation executes.
   *
   * @return WeakRef to this connection
   *
   * @note Thread Safety: This method is thread-safe.
   *
   * @note The WeakRef should be used with lock() to safely access the
   * connection. If lock() returns null, the connection has been destroyed.
   *
   * Example usage:
   * ```cpp
   * auto weak_conn = conn.get_weak_ref();
   * async_processor.submit([weak_conn, request_data]() {
   *   if (auto conn = weak_conn.lock()) {
   *     Arena arena;
   *     auto response = process_request(request_data, arena);
   *     conn->append_message({&response, 1}, std::move(arena));
   *   }
   * });
   * ```
   */
  WeakRef<MessageSender> get_weak_ref() const {
    assert(self_ref_.lock());
    return self_ref_.copy();
  }

  /**
   * @brief Get the unique identifier for this connection.
   *
   * Returns a server-generated unique ID that can be used for logging,
   * debugging, or tracking individual connections. The ID is assigned
   * atomically when the connection is created and remains constant throughout
   * the connection's lifetime.
   *
   * @return Unique 64-bit connection identifier
   *
   * @note Thread Safety: This method is thread-safe as it only reads an
   * immutable value set during construction.
   *
   * @note The ID is generated using an atomic counter, ensuring uniqueness
   * across all connections within a single server instance. IDs are not
   * guaranteed to be sequential due to concurrent connection creation.
   *
   * Typical usage:
   * ```cpp
   * std::cout << "Processing request on connection " << conn->get_id() <<
   * std::endl; logger.info("Connection {} sent {} bytes", conn->get_id(),
   * response.size());
   * ```
   */
  int64_t get_id() const { return id_; }

  /**
   * @brief Get the number of bytes queued for transmission.
   *
   * Returns the total number of bytes in all messages currently
   * queued for transmission to the client. This includes all data added via
   * append_message() that has not yet been sent over the network.
   *
   * @return Total bytes queued for transmission
   *
   * @warning Thread Safety: Only call from the thread that currently owns this
   * connection. Concurrent access to the message queue is not thread-safe.
   *
   * @note Performance: This method uses an O(1) counter for fast retrieval
   * in release builds. In debug builds, validates counter accuracy.
   *
   * @note The count decreases as the server sends data via writeBytes() and
   * removes completed messages from the queue.
   *
   * Use cases:
   * ```cpp
   * // Check if all data has been sent
   * if (conn->outgoing_bytes_queued() == 0) {
   *     conn->reset();  // Safe to reset arena
   * }
   *
   * // Implement backpressure
   * if (conn->outgoing_bytes_queued() > MAX_BUFFER_SIZE) {
   *     // Stop adding more data until queue drains
   * }
   *
   * // Logging/monitoring
   * metrics.recordQueueDepth(conn->get_id(), conn->outgoing_bytes_queued());
   * ```
   */
  int64_t outgoing_bytes_queued() const {
    std::lock_guard lock(mutex_);
#ifndef NDEBUG
    // Debug build: validate counter accuracy
    int64_t computed_total = 0;
    for (const auto &message : message_queue_) {
      for (const auto &part : message.data_parts) {
        computed_total += part.size();
      }
    }
    assert(
        outgoing_bytes_queued_ == computed_total &&
        "outgoing_bytes_queued_ counter is out of sync with actual queue size");
#endif
    return outgoing_bytes_queued_;
  }

  /**
   * @brief Protocol-specific data pointer for handler use.
   *
   * A void pointer that can be used by ConnectionHandler implementations to
   * attach protocol-specific state or data structures to individual
   * connections. This enables handlers to maintain per-connection state without
   * requiring external lookup tables.
   *
   * @warning Memory Management: The handler is responsible for allocating and
   * freeing any data pointed to by user_data. Typically this should be done in
   * on_connection_established() and on_connection_closed() respectively.
   *
   * @warning Thread Safety: Only access from the thread that currently owns
   * this connection. The pointer itself and any referenced data must not be
   * accessed concurrently.
   *
   * @note Lifetime: The user_data pointer is set to nullptr in the destructor
   * for safety, but the handler must ensure proper cleanup in
   * on_connection_closed() before the connection is destroyed.
   *
   * Example usage:
   * ```cpp
   * class HttpHandler : public ConnectionHandler {
   *   void on_connection_established(Connection& conn) override {
   *     // Allocate HTTP state in connection's arena or heap
   *     auto* state = conn.get_arena().construct<HttpConnectionState>();
   *     conn.user_data = state;
   *   }
   *
   *   void on_connection_closed(Connection& conn) override {
   *     // Cleanup if using heap allocation
   *     delete static_cast<HttpConnectionState*>(conn.user_data);
   *     conn.user_data = nullptr;
   *   }
   *
   *   void on_data_arrived(std::string_view data,
   *                        Ref<Connection>& conn_ptr) override {
   *     auto* state = static_cast<HttpConnectionState*>(conn_ptr->user_data);
   *     // Use state for protocol processing...
   *   }
   * };
   * ```
   */
  void *user_data = nullptr;

private:
  struct Message {
    Arena arena;                            // Owns all the memory (movable)
    std::span<std::string_view> data_parts; // Points to arena-allocated memory
                                            // (mutable for partial writes)
    bool close_after_send = false;          // Close connection after sending
  };

  // Server is a friend and can access all networking internals
  friend struct Server;

  /**
   * @brief Private constructor - only accessible by Server.
   *
   * Creates a new connection with the specified network address, file
   * descriptor, and associated handler. Automatically increments the global
   * active connection counter and calls the handler's
   * on_connection_established() method.
   *
   * @param addr Network address of the remote client (IPv4/IPv6 compatible)
   * @param fd File descriptor for the socket connection
   * @param id Unique connection identifier generated by the server
   * @param handler Protocol handler for processing connection data
   * @param server Reference to server associated with this connection
   */
  Connection(struct sockaddr_storage addr, int fd, int64_t id,
             size_t epoll_index, ConnectionHandler *handler,
             WeakRef<Server> server);

  template <typename T, typename... Args>
  friend Ref<T> make_ref(Args &&...args);

  // Networking interface - only accessible by Server
  int readBytes(char *buf, size_t buffer_size);
  enum WriteBytesResult {
    Error = 1 << 0,
    Progress = 1 << 1,
    Drained = 1 << 2,
    Close = 1 << 3,
  };
  uint32_t write_bytes();

  // Direct access methods for Server (must hold mutex)
  int getFd() const { return fd_; }
  bool has_messages() const { return !message_queue_.empty(); }
  size_t getEpollIndex() const { return epoll_index_; }
  void close();

  // Immutable connection properties
  int fd_;
  const int64_t id_;
  const size_t epoll_index_; // Index of the epoll instance this connection uses
  struct sockaddr_storage addr_; // sockaddr_storage handles IPv4/IPv6
  ConnectionHandler *const handler_;
  WeakRef<Server> server_;       // Weak reference to server for safe cleanup
  WeakRef<Connection> self_ref_; // WeakRef to self for get_weak_ref()

  // Thread-safe state (protected by mutex_)
  mutable std::mutex mutex_; // Protects all mutable state
  std::deque<Message>
      message_queue_; // Queue of messages to send. Protectec by
                      // mutex_, but if non-empty mutex_ can be
                      // dropped while server accesses existing elements.
  int64_t outgoing_bytes_queued_{0}; // Counter of queued bytes

#if __has_feature(thread_sanitizer)
  void tsan_acquire() { tsan_sync.load(std::memory_order_acquire); }
  void tsan_release() { tsan_sync.store(0, std::memory_order_release); }
  std::atomic<int> tsan_sync;
#else
  void tsan_acquire() {}
  void tsan_release() {}
#endif
};
