/* This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License. For a copy,
 * see http://www.gnu.org/licenses/gpl-2.0.html.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 */

#ifndef _HTTP2_H
#define _HTTP2_H

#include "config.h"

#ifdef ENABLE_HTTP2

#include <stdint.h>
#include <nghttp2/nghttp2.h>
#include "global.h"
#include "session.h"

#define H2_MAX_CONCURRENT_STREAMS   128    /* default; overridden by H2MaxConcurrentStreams */
#define H2_MAX_QUEUED_PER_CONN      256    /* per-connection dispatch queue depth;
                                            * 2x H2_MAX_CONCURRENT_STREAMS to absorb
                                            * burst completions between drain cycles */
#define H2_READ_BUFFER_SIZE        (16 * KILOBYTE)
#define H2_MAX_HEADER_VALUE_LEN    8192
#define H2_MAX_HEADER_LIST_SIZE   65536
#define H2_IDLE_TIMEOUT            300    /* seconds */
#define H2_CLOSING_TIMEOUT          30    /* seconds: max wait for pending workers */
#define H2_INITIAL_CONN_CAPACITY    64
#define H2_MAX_RESPONSE_SIZE      (128 * MEGABYTE)  /* 128 MB per-stream response buffer limit */
#define H2_MAX_CONNECTIONS        1024    /* max concurrent HTTP/2 connections in event loop */
#define H2_MAX_WORKERS            2048    /* max concurrent H2 worker threads;
                                           * prevents pthread_create() exhaustion
                                           * under burst load (100c × 32 streams).
                                           * must be high enough for steady-state
                                           * throughput, low enough to prevent
                                           * OS thread limit exhaustion */

typedef struct type_http2_stream {
	int32_t         stream_id;

	/* Pseudo-headers from HPACK */
	char            *method;
	char            *path;
	char            *authority;
	char            *scheme;

	/* Regular headers collected during HPACK decode */
	t_http_header   *headers;
	size_t          header_list_size;

	/* Request body */
	char            *body;
	size_t          body_size;
	size_t          body_capacity;

	/* Stream state */
	bool            headers_complete;
	bool            request_complete;

	struct type_http2_stream *next;
} t_http2_stream;

typedef struct type_http2_connection {
	nghttp2_session   *ng_session;
	t_session         *base_session;    /* TLS connection, socket, binding, config */

	t_http2_stream    *streams;
	int               active_streams;

	/* Event-loop fields */
	bool              closing;
	bool              client_removed; /* client record already released */
	bool              write_blocked;  /* mbedtls returned WANT_WRITE — needs POLLOUT */
	time_t            last_activity;
	time_t            closing_since;  /* when closing was first set */
	int               pending_requests;
	int               requests_served;  /* total streams completed on this connection */

	/* Dispatch queue: completed requests waiting for worker threads.
	 * Singly-linked FIFO via work_item->next.  Items are enqueued by
	 * on_frame_recv_callback() and drained by h2_drain_dispatch_queue().
	 * Only the event loop thread accesses these — no mutex needed.
	 * Flushed (freed without dispatch) on connection close and shutdown.
	 */
	struct type_h2_work_item *queue_head;
	struct type_h2_work_item *queue_tail;
	int               queued_count;
} t_http2_connection;

/* Work item: event loop dispatches completed request to worker thread */
typedef struct type_h2_work_item {
	t_http2_connection  *conn;
	int32_t             stream_id;

	/* Deep-copies from the stream */
	char                *method;
	char                *path;
	char                *authority;
	t_http_header       *headers;
	char                *body;
	size_t              body_size;

	/* Read-only references shared with event loop */
	t_config            *config;
	t_binding           *binding;
	t_ip_addr           ip_address;

	const char          *tls_version;
	const char          *tls_cipher;

	struct type_h2_work_item *next;
} t_h2_work_item;

/* Response item: worker returns completed response to event loop */
typedef struct type_h2_response_item {
	t_http2_connection  *conn;
	int32_t             stream_id;

	/* Buffered HTTP/1.1 response (ownership transferred) */
	char                *response_buf;
	size_t              response_size;

	/* Log data for deferred logging */
	int                 return_code;
	bool                log_request;
	off_t               bytes_sent;
	char                *log_uri;
	t_req_method        request_method;

	struct type_h2_response_item *next;
} t_h2_response_item;

/* Event loop API */
int  h2_event_loop_init(t_config *config);
void h2_event_loop_shutdown(void);
void h2_graceful_shutdown(int timeout_seconds);
int  h2_event_loop_add_connection(t_session *session);

/* Worker-facing function: process a dispatched H2 request */
void h2_worker_process(t_h2_work_item *item);

#endif /* ENABLE_HTTP2 */

#endif
