//! HTTP/1.0 and HTTP/1.1 connection handling (struct-based, zero-copy parsing)

use super::SendfileSupport;
use super::detector;
use super::handler::HttpConnectionHandler;
use crate::config::ServerConfig;
use crate::errors::{FalcornError, Result};
use crate::http::{Body, HttpMethod, HttpRequest, HttpResponse};
use crate::logging::{Logger, ipc::AccessRecord};
use crate::runtime::{BufferPool, PooledBuffer};
use crate::server::request_handler::RequestHandler;
use bytes::{Buf, Bytes, BytesMut};
use std::io::{Read, Seek, SeekFrom, Write};
use std::net::SocketAddr;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::{Duration, Instant};
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use tokio::time::timeout;

const MAX_HEADER_BYTES: usize = 64 * 1024;
const MAX_CHUNKED_BODY_BYTES: usize = 16 * 1024 * 1024;

pub(crate) trait ReadTimeout {
    fn set_read_timeout(&mut self, timeout: Option<Duration>) -> std::io::Result<()>;
}

impl ReadTimeout for std::net::TcpStream {
    fn set_read_timeout(&mut self, timeout: Option<Duration>) -> std::io::Result<()> {
        std::net::TcpStream::set_read_timeout(self, timeout)
    }
}

#[cfg(feature = "ssl")]
impl<C, T> ReadTimeout for rustls::StreamOwned<C, T>
where
    T: ReadTimeout + Read + Write,
{
    fn set_read_timeout(&mut self, timeout: Option<Duration>) -> std::io::Result<()> {
        self.sock.set_read_timeout(timeout)
    }
}

#[derive(Debug, Clone, Copy)]
enum BodyKind {
    None,
    ContentLength(usize),
    Chunked,
}

#[derive(Debug)]
struct ConnBuf {
    data: PooledBuffer,
}

impl ConnBuf {
    fn new(pool: BufferPool, data: Vec<u8>) -> Self {
        let mut buf = PooledBuffer::new(pool, data.len().max(512));
        buf.buffer_mut().extend_from_slice(&data);
        Self { data: buf }
    }

    fn empty(pool: BufferPool) -> Self {
        Self {
            data: PooledBuffer::new(pool, 512),
        }
    }

    fn bytes(&self) -> &BytesMut {
        self.data.buffer()
    }

    fn bytes_mut(&mut self) -> &mut BytesMut {
        self.data.buffer_mut()
    }
}

/// HTTP/1 handler (sync + async)
#[derive(Clone)]
pub struct Http1Handler {
    pool: BufferPool,
}

impl Default for Http1Handler {
    fn default() -> Self {
        Self {
            pool: BufferPool::with_default_max(4096),
        }
    }
}

impl Http1Handler {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn with_pool(pool: BufferPool) -> Self {
        Self { pool }
    }

    pub fn serve_connection_sync<S: Read + Write + ReadTimeout + SendfileSupport>(
        &self,
        mut stream: S,
        peer_addr: SocketAddr,
        handler: &RequestHandler,
        logger: &Logger,
        config: &ServerConfig,
        initial: Vec<u8>,
        request_count: Option<&AtomicUsize>,
    ) -> Result<()> {
        let mut buf = ConnBuf::new(self.pool.clone(), initial);
        loop {
            let req = self.read_request_sync(
                &mut stream,
                &mut buf,
                peer_addr,
                config.buffer_size,
                config.keepalive_timeout,
                config.worker_timeout,
            )?;

            let req = match req {
                Some(r) => r,
                None => break,
            };

            if let Some(counter) = request_count {
                counter.fetch_add(1, Ordering::Relaxed);
            }

            let started_at = Instant::now();
            let (mut resp, is_error) = match handler.handle_sync(&req) {
                Ok(resp) => (resp, false),
                Err(err) => {
                    logger.error(|| format!("Request error: {}", err));
                    (handler.handle_error_with_request(err, Some(&req)), true)
                }
            };
            let body_len = resp.body_len().unwrap_or(0);

            // let resp = super::super::response().text("test").build();
            // let is_error = false;

            self.write_response_sync(&mut stream, &mut resp, &req)?;
            self.log_access(
                logger,
                &req,
                resp.status.as_u16(),
                body_len,
                started_at.elapsed(),
            );

            if is_error || !req.is_keep_alive() {
                break;
            }
        }
        Ok(())
    }

    pub async fn serve_connection_async<S: AsyncRead + AsyncWrite + Unpin>(
        &self,
        mut stream: S,
        peer_addr: SocketAddr,
        handler: RequestHandler,
        logger: Logger,
        config: Arc<ServerConfig>,
        initial: Vec<u8>,
        request_count: Option<std::sync::Arc<AtomicUsize>>,
    ) -> Result<()> {
        let mut buf = ConnBuf::new(self.pool.clone(), initial);

        loop {
            let req = self
                .read_request_async(
                    &mut stream,
                    &mut buf,
                    peer_addr,
                    config.buffer_size,
                    config.keepalive_timeout,
                    config.worker_timeout,
                )
                .await?;

            let req = match req {
                Some(r) => r,
                None => break,
            };

            if let Some(counter) = request_count.as_ref() {
                counter.fetch_add(1, Ordering::Relaxed);
            }

            let started_at = Instant::now();
            let (mut resp, is_error) = match handler.handle_async(&req).await {
                Ok(resp) => (resp, false),
                Err(err) => (handler.handle_error_with_request(err, Some(&req)), true),
            };
            let body_len = resp.body_len().unwrap_or(0);

            self.write_response_async(&mut stream, &mut resp, &req)
                .await?;
            self.log_access(
                &logger,
                &req,
                resp.status.as_u16(),
                body_len,
                started_at.elapsed(),
            );

            if is_error || !req.is_keep_alive() {
                break;
            }
        }

        let _ = stream.shutdown().await;
        Ok(())
    }

    fn read_request_sync<S: Read + Write + ReadTimeout>(
        &self,
        stream: &mut S,
        buf: &mut ConnBuf,
        peer_addr: SocketAddr,
        read_chunk: usize,
        keepalive_timeout: u64,
        worker_timeout: u64,
    ) -> Result<Option<HttpRequest>> {
        loop {
            let timeout_secs = if buf.bytes().is_empty() {
                keepalive_timeout
            } else {
                worker_timeout
            };
            let _ = stream.set_read_timeout(Some(Duration::from_secs(timeout_secs)));

            if detector::looks_like_http2_preface(buf.bytes()) {
                return Err(FalcornError::runtime(
                    "HTTP/2 preface received on HTTP/1.x handler",
                ));
            }

            if find_headers_end(buf.bytes()).is_some() {
                break;
            }

            if buf.bytes().len() > MAX_HEADER_BYTES {
                return Err(FalcornError::http_parse("Request headers too large"));
            }

            let n = read_into_pooled_sync(stream, &mut buf.data, read_chunk.max(512))?;
            if n == 0 {
                // EOF / connection closed by peer.
                // Treat it as a graceful close:
                // - if nothing buffered => normal connection close (no request)
                // - if partial data buffered => client closed mid-request; do not treat as server error
                return Ok(None);
            }
        }

        let header_end = find_headers_end(buf.bytes())
            .ok_or_else(|| FalcornError::http_parse("Incomplete HTTP headers"))?;
        let raw = buf.bytes_mut().split_to(header_end + 4).freeze();
        let (mut req, body_kind) = parse_headers_zero_copy(raw, header_end, peer_addr)?;

        if req.expects_continue()
            && matches!(body_kind, BodyKind::ContentLength(_) | BodyKind::Chunked)
        {
            self.send_continue_sync(stream, req.version)?;
        }

        let body = match body_kind {
            BodyKind::None => None,
            BodyKind::ContentLength(len) => {
                Some(self.read_fixed_body_sync(stream, buf, len, worker_timeout)?)
            }
            BodyKind::Chunked => Some(Bytes::from(self.read_chunked_body_sync(
                stream,
                buf,
                worker_timeout,
            )?)),
        };

        if let Some(body_bytes) = body {
            if !body_bytes.is_empty() {
                req.body = Some(std::sync::Arc::new(body_bytes));
            }
        }

        Ok(Some(req))
    }

    async fn read_request_async<S: AsyncRead + AsyncWrite + Unpin>(
        &self,
        stream: &mut S,
        buf: &mut ConnBuf,
        peer_addr: SocketAddr,
        read_chunk: usize,
        _keepalive_timeout: u64,
        worker_timeout: u64,
    ) -> Result<Option<HttpRequest>> {
        loop {
            if detector::looks_like_http2_preface(buf.bytes()) {
                return Err(FalcornError::runtime(
                    "HTTP/2 preface received on HTTP/1.x handler",
                ));
            }

            if find_headers_end(buf.bytes()).is_some() {
                break;
            }

            if buf.bytes().len() > MAX_HEADER_BYTES {
                return Err(FalcornError::http_parse("Request headers too large"));
            }

            let n = timeout(
                Duration::from_secs(_keepalive_timeout),
                read_into_pooled_async(stream, &mut buf.data, read_chunk.max(512)),
            )
            .await
            .map_err(|_| FalcornError::RequestTimeout {
                seconds: _keepalive_timeout,
            })??;

            if n == 0 {
                // EOF / connection closed by peer.
                // Treat it as a graceful close:
                // - if nothing buffered => normal connection close (no request)
                // - if partial data buffered => client closed mid-request; do not treat as server error
                return Ok(None);
            }
        }

        let header_end = find_headers_end(buf.bytes())
            .ok_or_else(|| FalcornError::http_parse("Incomplete HTTP headers"))?;
        let raw = buf.bytes_mut().split_to(header_end + 4).freeze();
        let (mut req, body_kind) = parse_headers_zero_copy(raw, header_end, peer_addr)?;

        if req.expects_continue()
            && matches!(body_kind, BodyKind::ContentLength(_) | BodyKind::Chunked)
        {
            self.send_continue_async(stream, req.version).await?;
        }

        let body = match body_kind {
            BodyKind::None => None,
            BodyKind::ContentLength(len) => Some(
                self.read_fixed_body_async(stream, buf, len, worker_timeout)
                    .await?,
            ),
            BodyKind::Chunked => Some(Bytes::from(
                self.read_chunked_body_async(stream, buf, worker_timeout)
                    .await?,
            )),
        };

        if let Some(body_bytes) = body {
            if !body_bytes.is_empty() {
                req.body = Some(std::sync::Arc::new(body_bytes));
            }
        }

        Ok(Some(req))
    }

    fn read_fixed_body_sync<S: Read + ReadTimeout>(
        &self,
        stream: &mut S,
        buf: &mut ConnBuf,
        len: usize,
        worker_timeout: u64,
    ) -> Result<Bytes> {
        let _ = stream.set_read_timeout(Some(Duration::from_secs(worker_timeout)));
        ensure_available_sync(stream, &mut buf.data, len)?;
        Ok(buf.bytes_mut().split_to(len).freeze())
    }

    async fn read_fixed_body_async<S: AsyncRead + Unpin>(
        &self,
        stream: &mut S,
        buf: &mut ConnBuf,
        len: usize,
        worker_timeout: u64,
    ) -> Result<Bytes> {
        ensure_available_async(stream, &mut buf.data, len, worker_timeout).await?;
        Ok(buf.bytes_mut().split_to(len).freeze())
    }

    fn read_chunked_body_sync<S: Read + ReadTimeout>(
        &self,
        stream: &mut S,
        buf: &mut ConnBuf,
        worker_timeout: u64,
    ) -> Result<Vec<u8>> {
        let _ = stream.set_read_timeout(Some(Duration::from_secs(worker_timeout)));
        let mut idx = 0;
        let mut body = Vec::new();

        loop {
            let line = self.read_line_sync(stream, buf, &mut idx, worker_timeout)?;
            let line = line.trim();
            let size = usize::from_str_radix(line, 16)
                .map_err(|_| FalcornError::http_parse("Invalid chunk size"))?;
            if size == 0 {
                self.consume_trailers_sync(stream, buf, &mut idx, worker_timeout)?;
                break;
            }
            if body.len().saturating_add(size) > MAX_CHUNKED_BODY_BYTES {
                return Err(FalcornError::PayloadTooLarge {
                    limit: MAX_CHUNKED_BODY_BYTES,
                });
            }
            ensure_available_sync(stream, &mut buf.data, idx + size + 2)?;
            body.extend_from_slice(&buf.bytes()[idx..idx + size]);
            idx += size + 2;
        }

        let remaining = buf.bytes_mut().split_off(idx);
        *buf.bytes_mut() = remaining;
        Ok(body)
    }

    async fn read_chunked_body_async<S: AsyncRead + Unpin>(
        &self,
        stream: &mut S,
        buf: &mut ConnBuf,
        worker_timeout: u64,
    ) -> Result<Vec<u8>> {
        let mut idx = 0;
        let mut body = Vec::new();

        loop {
            let line = self
                .read_line_async(stream, buf, &mut idx, worker_timeout)
                .await?;
            let line = line.trim();
            let size = usize::from_str_radix(line, 16)
                .map_err(|_| FalcornError::http_parse("Invalid chunk size"))?;
            if size == 0 {
                self.consume_trailers_async(stream, buf, &mut idx, worker_timeout)
                    .await?;
                break;
            }
            if body.len().saturating_add(size) > MAX_CHUNKED_BODY_BYTES {
                return Err(FalcornError::PayloadTooLarge {
                    limit: MAX_CHUNKED_BODY_BYTES,
                });
            }
            ensure_available_async(stream, &mut buf.data, idx + size + 2, worker_timeout).await?;
            body.extend_from_slice(&buf.bytes()[idx..idx + size]);
            idx += size + 2;
        }

        let remaining = buf.bytes_mut().split_off(idx);
        *buf.bytes_mut() = remaining;
        Ok(body)
    }

    fn read_line_sync<S: Read + ReadTimeout>(
        &self,
        stream: &mut S,
        buf: &mut ConnBuf,
        idx: &mut usize,
        worker_timeout: u64,
    ) -> Result<String> {
        loop {
            if let Some(pos) = find_crlf(&buf.bytes()[*idx..]) {
                let end = *idx + pos;
                let line = std::str::from_utf8(&buf.bytes()[*idx..end])
                    .map_err(|_| FalcornError::http_parse("Invalid chunk line"))?
                    .to_string();
                *idx = end + 2;
                return Ok(line);
            }
            let _ = stream.set_read_timeout(Some(Duration::from_secs(worker_timeout)));
            let needed = buf.bytes().len() + 1;
            ensure_available_sync(stream, &mut buf.data, needed)?;
        }
    }

    async fn read_line_async<S: AsyncRead + Unpin>(
        &self,
        stream: &mut S,
        buf: &mut ConnBuf,
        idx: &mut usize,
        worker_timeout: u64,
    ) -> Result<String> {
        loop {
            if let Some(pos) = find_crlf(&buf.bytes()[*idx..]) {
                let end = *idx + pos;
                let line = std::str::from_utf8(&buf.bytes()[*idx..end])
                    .map_err(|_| FalcornError::http_parse("Invalid chunk line"))?
                    .to_string();
                *idx = end + 2;
                return Ok(line);
            }
            let needed = buf.bytes().len() + 1;
            ensure_available_async(stream, &mut buf.data, needed, worker_timeout).await?;
        }
    }

    fn consume_trailers_sync<S: Read + ReadTimeout>(
        &self,
        stream: &mut S,
        buf: &mut ConnBuf,
        idx: &mut usize,
        worker_timeout: u64,
    ) -> Result<()> {
        loop {
            let line = self.read_line_sync(stream, buf, idx, worker_timeout)?;
            if line.is_empty() {
                return Ok(());
            }
        }
    }

    async fn consume_trailers_async<S: AsyncRead + Unpin>(
        &self,
        stream: &mut S,
        buf: &mut ConnBuf,
        idx: &mut usize,
        worker_timeout: u64,
    ) -> Result<()> {
        loop {
            let line = self
                .read_line_async(stream, buf, idx, worker_timeout)
                .await?;
            if line.is_empty() {
                return Ok(());
            }
        }
    }

    fn write_response_sync<S: Write + SendfileSupport>(
        &self,
        stream: &mut S,
        response: &mut HttpResponse,
        request: &HttpRequest,
    ) -> Result<()> {
        let mut extra_headers = Vec::new();
        let mut force_close = !request.is_keep_alive();
        let mut chunked = false;

        let mut body_len = response.body.len();
        if body_len.is_none() {
            if let Body::File { path, offset, len } = &response.body {
                body_len = file_len(path, *offset, *len);
            }
        }
        let has_cl = response.headers.contains_key(http::header::CONTENT_LENGTH);
        let has_te = response
            .headers
            .contains_key(http::header::TRANSFER_ENCODING);
        let te_is_chunked = header_has_chunked(&response.headers);

        match body_len {
            Some(len) => {
                if !has_cl && !has_te {
                    extra_headers.push((
                        http::header::CONTENT_LENGTH,
                        http::HeaderValue::from_str(&len.to_string()).map_err(|e| {
                            FalcornError::runtime(format!("Invalid content-length: {}", e))
                        })?,
                    ));
                } else if te_is_chunked {
                    chunked = true;
                }
            }
            None => {
                if request.version == http::Version::HTTP_11 {
                    if !has_te {
                        extra_headers.push((
                            http::header::TRANSFER_ENCODING,
                            http::HeaderValue::from_static("chunked"),
                        ));
                    }
                    chunked = true;
                } else {
                    // HTTP/1.0 requires close-delimited bodies.
                    force_close = true;
                }
            }
        }

        if force_close && !response.headers.contains_key(http::header::CONNECTION) {
            extra_headers.push((
                http::header::CONNECTION,
                http::HeaderValue::from_static("close"),
            ));
        }

        let head = build_response_head(response, request.version, &extra_headers);
        stream.write_all(&head).map_err(FalcornError::IoError)?;

        match &mut response.body {
            Body::Empty => {}
            Body::Bytes(bytes) => {
                if chunked {
                    write_chunked_sync(stream, bytes)?;
                } else if !bytes.is_empty() {
                    stream.write_all(bytes).map_err(FalcornError::IoError)?;
                }
            }
            Body::SyncReader(reader) => {
                if chunked {
                    write_reader_chunked_sync(stream, reader.as_mut())?;
                } else {
                    write_reader_raw_sync(stream, reader.as_mut())?;
                }
            }
            Body::AsyncStream(_) => {
                return Err(FalcornError::runtime(
                    "Async body stream cannot be sent from sync writer",
                ));
            }
            Body::File { path, offset, len } => {
                write_file_sync(stream, path, *offset, *len, chunked)?;
            }
        }

        stream.flush().map_err(FalcornError::IoError)?;
        Ok(())
    }

    async fn write_response_async<S: AsyncWrite + Unpin>(
        &self,
        stream: &mut S,
        response: &mut HttpResponse,
        request: &HttpRequest,
    ) -> Result<()> {
        let mut extra_headers = Vec::new();
        let mut force_close = !request.is_keep_alive();
        let mut chunked = false;

        let mut body_len = response.body.len();
        if body_len.is_none() {
            if let Body::File { path, offset, len } = &response.body {
                body_len = file_len(path, *offset, *len);
            }
        }
        let has_cl = response.headers.contains_key(http::header::CONTENT_LENGTH);
        let has_te = response
            .headers
            .contains_key(http::header::TRANSFER_ENCODING);
        let te_is_chunked = header_has_chunked(&response.headers);

        match body_len {
            Some(len) => {
                if !has_cl && !has_te {
                    extra_headers.push((
                        http::header::CONTENT_LENGTH,
                        http::HeaderValue::from_str(&len.to_string()).map_err(|e| {
                            FalcornError::runtime(format!("Invalid content-length: {}", e))
                        })?,
                    ));
                } else if te_is_chunked {
                    chunked = true;
                }
            }
            None => {
                if request.version == http::Version::HTTP_11 {
                    if !has_te {
                        extra_headers.push((
                            http::header::TRANSFER_ENCODING,
                            http::HeaderValue::from_static("chunked"),
                        ));
                    }
                    chunked = true;
                } else {
                    force_close = true;
                }
            }
        }

        if force_close && !response.headers.contains_key(http::header::CONNECTION) {
            extra_headers.push((
                http::header::CONNECTION,
                http::HeaderValue::from_static("close"),
            ));
        }

        let head = build_response_head(response, request.version, &extra_headers);
        stream
            .write_all(&head)
            .await
            .map_err(FalcornError::IoError)?;

        match &mut response.body {
            Body::Empty => {}
            Body::Bytes(bytes) => {
                if chunked {
                    write_chunked_async(stream, bytes).await?;
                } else if !bytes.is_empty() {
                    stream
                        .write_all(bytes)
                        .await
                        .map_err(FalcornError::IoError)?;
                }
            }
            Body::SyncReader(reader) => {
                let mut buf = Vec::new();
                reader
                    .read_to_end(&mut buf)
                    .map_err(FalcornError::IoError)?;
                let bytes = bytes::Bytes::from(buf);
                if chunked {
                    write_chunked_async(stream, &bytes).await?;
                } else if !bytes.is_empty() {
                    stream
                        .write_all(&bytes)
                        .await
                        .map_err(FalcornError::IoError)?;
                }
            }
            Body::AsyncStream(body_stream) => {
                if chunked {
                    write_stream_chunked_async(stream, body_stream).await?;
                } else {
                    write_stream_raw_async(stream, body_stream).await?;
                }
            }
            Body::File { path, offset, len } => {
                write_file_async(stream, path, *offset, *len, chunked).await?;
            }
        }

        stream.flush().await.map_err(FalcornError::IoError)?;
        Ok(())
    }

    fn send_continue_sync<S: Write>(&self, stream: &mut S, version: http::Version) -> Result<()> {
        let line = match version {
            http::Version::HTTP_10 => b"HTTP/1.0 100 Continue\r\n\r\n".to_vec(),
            _ => b"HTTP/1.1 100 Continue\r\n\r\n".to_vec(),
        };
        stream.write_all(&line).map_err(FalcornError::IoError)?;
        stream.flush().map_err(FalcornError::IoError)?;
        Ok(())
    }

    async fn send_continue_async<S: AsyncWrite + Unpin>(
        &self,
        stream: &mut S,
        version: http::Version,
    ) -> Result<()> {
        let line = match version {
            http::Version::HTTP_10 => b"HTTP/1.0 100 Continue\r\n\r\n".to_vec(),
            _ => b"HTTP/1.1 100 Continue\r\n\r\n".to_vec(),
        };
        stream
            .write_all(&line)
            .await
            .map_err(FalcornError::IoError)?;
        stream.flush().await.map_err(FalcornError::IoError)?;
        Ok(())
    }

    fn log_access(
        &self,
        logger: &Logger,
        request: &HttpRequest,
        status: u16,
        size: usize,
        duration: Duration,
    ) {
        let record = AccessRecord {
            remote: request.peer_addr.ip().to_string(),
            method: request.method.as_str().to_string(),
            uri: request.uri(),
            version: request.version_str().to_string(),
            status,
            size,
            duration_micros: duration.as_micros().min(u128::from(u64::MAX)) as u64,
        };

        logger.access_record(record);
    }
}

impl HttpConnectionHandler for Http1Handler {
    fn handle_sync<S: Read + Write + ReadTimeout + SendfileSupport>(
        &self,
        stream: S,
        peer_addr: SocketAddr,
        handler: &RequestHandler,
        logger: &Logger,
        config: &ServerConfig,
        initial: Vec<u8>,
        request_count: Option<&AtomicUsize>,
    ) -> Result<()> {
        self.serve_connection_sync(
            stream,
            peer_addr,
            handler,
            logger,
            config,
            initial,
            request_count,
        )
    }

    fn handle_async<'a, S>(
        &'a self,
        stream: S,
        peer_addr: SocketAddr,
        handler: RequestHandler,
        logger: Logger,
        config: Arc<ServerConfig>,
        initial: Vec<u8>,
        request_count: Option<std::sync::Arc<AtomicUsize>>,
    ) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<()>> + Send + 'a>>
    where
        S: AsyncRead + AsyncWrite + Unpin + Send + 'a,
    {
        Box::pin(self.serve_connection_async(
            stream,
            peer_addr,
            handler,
            logger,
            config,
            initial,
            request_count,
        ))
    }
}

fn parse_headers_zero_copy(
    raw: Bytes,
    header_end: usize,
    peer_addr: SocketAddr,
) -> Result<(HttpRequest, BodyKind)> {
    let mut headers = [httparse::EMPTY_HEADER; 64];
    let mut req = httparse::Request::new(&mut headers);

    let (method, version, header_map, body_kind, path_range, query_range) = {
        let raw_ref = raw.clone();
        let data = raw_ref.as_ref();

        let parse_len = (header_end + 4).min(data.len());
        let status = req
            .parse(&data[..parse_len])
            .map_err(|e| FalcornError::http_parse(format!("Invalid HTTP request: {}", e)))?;

        if status.is_partial() {
            return Err(FalcornError::http_parse("Partial HTTP request"));
        }

        let method = req
            .method
            .ok_or_else(|| FalcornError::http_parse("Missing method"))?;
        let method = HttpMethod::from_str(method)?;
        let path = req
            .path
            .ok_or_else(|| FalcornError::http_parse("Missing path"))?;

        let version = match req.version.unwrap_or(1) {
            0 => http::Version::HTTP_10,
            1 => http::Version::HTTP_11,
            _ => http::Version::HTTP_11,
        };

        let mut header_map: Vec<(Bytes, Bytes)> = Vec::with_capacity(req.headers.len());
        for h in req.headers {
            let mut name_lc = Vec::with_capacity(h.name.len());
            for b in h.name.as_bytes() {
                name_lc.push(b.to_ascii_lowercase());
            }
            header_map.push((
                Bytes::from(name_lc),
                raw_ref.slice(slice_range_for_header_value(data, h.value)),
            ));
        }

        let path_start = path.as_ptr() as usize - data.as_ptr() as usize;
        let path_end = path_start + path.len();

        let (path_range, query_range) = match path.find('?') {
            Some(idx) => {
                let path_range = path_start..(path_start + idx);
                let query_range = Some((path_start + idx + 1)..path_end);
                (path_range, query_range)
            }
            None => (path_start..path_end, None),
        };

        let body_kind = detect_body_kind(&header_map);
        (
            method,
            version,
            header_map,
            body_kind,
            path_range,
            query_range,
        )
    };

    let path_slice = raw.slice(path_range);
    let query_slice = query_range.map(|r| raw.slice(r));

    let req = HttpRequest {
        raw,
        method,
        path: path_slice,
        query_string: query_slice,
        version,
        headers: header_map,
        body: None,
        peer_addr,
    };

    Ok((req, body_kind))
}

fn detect_body_kind(headers: &[(Bytes, Bytes)]) -> BodyKind {
    if let Some(te) = header_value(headers, b"transfer-encoding") {
        if let Ok(v) = std::str::from_utf8(te) {
            if v.to_ascii_lowercase().contains("chunked") {
                return BodyKind::Chunked;
            }
        }
    }
    if let Some(cl) = header_value(headers, b"content-length") {
        if let Ok(v) = std::str::from_utf8(cl) {
            if let Ok(len) = v.parse::<usize>() {
                if len > 0 {
                    return BodyKind::ContentLength(len);
                }
            }
        }
    }
    BodyKind::None
}

fn header_value<'a>(headers: &'a [(Bytes, Bytes)], name: &[u8]) -> Option<&'a [u8]> {
    for (n, v) in headers {
        if n.as_ref() == name {
            return Some(v.as_ref());
        }
    }
    None
}

fn build_response_head(
    response: &HttpResponse,
    version: http::Version,
    extra_headers: &[(http::header::HeaderName, http::HeaderValue)],
) -> Vec<u8> {
    let version_str = match version {
        http::Version::HTTP_10 => "HTTP/1.0",
        http::Version::HTTP_11 => "HTTP/1.1",
        http::Version::HTTP_2 => "HTTP/2.0",
        http::Version::HTTP_3 => "HTTP/3.0",
        _ => "HTTP/1.1",
    };

    let mut head = Vec::with_capacity(256);
    let status_line = format!(
        "{} {} {}\r\n",
        version_str,
        response.status.as_u16(),
        response.status.canonical_reason().unwrap_or("Unknown")
    );
    head.extend_from_slice(status_line.as_bytes());

    for (name, value) in response.headers.iter() {
        head.extend_from_slice(name.as_str().as_bytes());
        head.extend_from_slice(b": ");
        head.extend_from_slice(value.as_bytes());
        head.extend_from_slice(b"\r\n");
    }

    for (name, value) in extra_headers {
        head.extend_from_slice(name.as_str().as_bytes());
        head.extend_from_slice(b": ");
        head.extend_from_slice(value.as_bytes());
        head.extend_from_slice(b"\r\n");
    }

    head.extend_from_slice(b"\r\n");
    head
}

fn header_has_chunked(headers: &http::HeaderMap) -> bool {
    headers
        .get(http::header::TRANSFER_ENCODING)
        .and_then(|v| v.to_str().ok())
        .map(|v| v.to_ascii_lowercase().contains("chunked"))
        .unwrap_or(false)
}

fn file_len(path: &std::path::Path, offset: u64, len: Option<u64>) -> Option<usize> {
    let len = match len {
        Some(v) => v,
        None => {
            let meta = std::fs::metadata(path).ok()?;
            let total = meta.len();
            total.saturating_sub(offset)
        }
    };
    usize::try_from(len).ok()
}

fn write_file_sync<S: Write + SendfileSupport>(
    stream: &mut S,
    path: &std::path::Path,
    offset: u64,
    len: Option<u64>,
    chunked: bool,
) -> Result<()> {
    let mut file = std::fs::File::open(path).map_err(FalcornError::IoError)?;
    if offset > 0 {
        file.seek(SeekFrom::Start(offset))
            .map_err(FalcornError::IoError)?;
    }

    if chunked {
        return write_reader_chunked_sync(stream, &mut file);
    }

    // Try sendfile first (Linux, plain TCP).
    if let Some(total_len) = len.or_else(|| {
        std::fs::metadata(path)
            .ok()
            .map(|m| m.len().saturating_sub(offset))
    }) {
        let mut remaining = total_len;
        if stream.try_sendfile(&mut file, offset, &mut remaining)? {
            return Ok(());
        }
    }

    write_reader_raw_sync(stream, &mut file)
}

async fn write_file_async<S: AsyncWrite + Unpin>(
    stream: &mut S,
    path: &std::path::Path,
    offset: u64,
    _len: Option<u64>,
    chunked: bool,
) -> Result<()> {
    use tokio::io::{AsyncReadExt, AsyncSeekExt};

    let mut file = tokio::fs::File::open(path)
        .await
        .map_err(FalcornError::IoError)?;
    if offset > 0 {
        file.seek(SeekFrom::Start(offset))
            .await
            .map_err(FalcornError::IoError)?;
    }

    let mut buf = [0u8; 8192];
    loop {
        let n = file.read(&mut buf).await.map_err(FalcornError::IoError)?;
        if n == 0 {
            break;
        }
        if chunked {
            let head = format!("{:X}\r\n", n);
            stream
                .write_all(head.as_bytes())
                .await
                .map_err(FalcornError::IoError)?;
            stream
                .write_all(&buf[..n])
                .await
                .map_err(FalcornError::IoError)?;
            stream
                .write_all(b"\r\n")
                .await
                .map_err(FalcornError::IoError)?;
        } else {
            stream
                .write_all(&buf[..n])
                .await
                .map_err(FalcornError::IoError)?;
        }
    }

    if chunked {
        stream
            .write_all(b"0\r\n\r\n")
            .await
            .map_err(FalcornError::IoError)?;
    }

    Ok(())
}

fn write_chunked_sync<S: Write>(stream: &mut S, bytes: &[u8]) -> Result<()> {
    if bytes.is_empty() {
        stream
            .write_all(b"0\r\n\r\n")
            .map_err(FalcornError::IoError)?;
        return Ok(());
    }
    let head = format!("{:X}\r\n", bytes.len());
    stream
        .write_all(head.as_bytes())
        .map_err(FalcornError::IoError)?;
    stream.write_all(bytes).map_err(FalcornError::IoError)?;
    stream
        .write_all(b"\r\n0\r\n\r\n")
        .map_err(FalcornError::IoError)?;
    Ok(())
}

async fn write_chunked_async<S: AsyncWrite + Unpin>(stream: &mut S, bytes: &[u8]) -> Result<()> {
    if bytes.is_empty() {
        stream
            .write_all(b"0\r\n\r\n")
            .await
            .map_err(FalcornError::IoError)?;
        return Ok(());
    }
    let head = format!("{:X}\r\n", bytes.len());
    stream
        .write_all(head.as_bytes())
        .await
        .map_err(FalcornError::IoError)?;
    stream
        .write_all(bytes)
        .await
        .map_err(FalcornError::IoError)?;
    stream
        .write_all(b"\r\n0\r\n\r\n")
        .await
        .map_err(FalcornError::IoError)?;
    Ok(())
}

fn write_reader_chunked_sync<S: Write>(stream: &mut S, reader: &mut dyn Read) -> Result<()> {
    let mut buf = [0u8; 8192];
    loop {
        let n = reader.read(&mut buf).map_err(FalcornError::IoError)?;
        if n == 0 {
            break;
        }
        let head = format!("{:X}\r\n", n);
        stream
            .write_all(head.as_bytes())
            .map_err(FalcornError::IoError)?;
        stream.write_all(&buf[..n]).map_err(FalcornError::IoError)?;
        stream.write_all(b"\r\n").map_err(FalcornError::IoError)?;
    }
    stream
        .write_all(b"0\r\n\r\n")
        .map_err(FalcornError::IoError)?;
    Ok(())
}

fn write_reader_raw_sync<S: Write>(stream: &mut S, reader: &mut dyn Read) -> Result<()> {
    let mut buf = [0u8; 8192];
    loop {
        let n = reader.read(&mut buf).map_err(FalcornError::IoError)?;
        if n == 0 {
            break;
        }
        stream.write_all(&buf[..n]).map_err(FalcornError::IoError)?;
    }
    Ok(())
}

async fn write_stream_chunked_async<S: AsyncWrite + Unpin>(
    stream: &mut S,
    body: &mut crate::http::body::AsyncBodyStream,
) -> Result<()> {
    use futures::stream::StreamExt;
    while let Some(chunk) = body.next().await {
        let bytes = chunk?;
        if bytes.is_empty() {
            continue;
        }
        let head = format!("{:X}\r\n", bytes.len());
        stream
            .write_all(head.as_bytes())
            .await
            .map_err(FalcornError::IoError)?;
        stream
            .write_all(&bytes)
            .await
            .map_err(FalcornError::IoError)?;
        stream
            .write_all(b"\r\n")
            .await
            .map_err(FalcornError::IoError)?;
    }
    stream
        .write_all(b"0\r\n\r\n")
        .await
        .map_err(FalcornError::IoError)?;
    Ok(())
}

async fn write_stream_raw_async<S: AsyncWrite + Unpin>(
    stream: &mut S,
    body: &mut crate::http::body::AsyncBodyStream,
) -> Result<()> {
    use futures::stream::StreamExt;
    while let Some(chunk) = body.next().await {
        let bytes = chunk?;
        if bytes.is_empty() {
            continue;
        }
        stream
            .write_all(&bytes)
            .await
            .map_err(FalcornError::IoError)?;
    }
    Ok(())
}

fn find_headers_end(data: &[u8]) -> Option<usize> {
    data.windows(4).position(|w| w == b"\r\n\r\n")
}

fn find_crlf(data: &[u8]) -> Option<usize> {
    data.windows(2).position(|w| w == b"\r\n")
}

fn read_into_pooled_sync<S: Read>(
    stream: &mut S,
    buf: &mut PooledBuffer,
    min_reserve: usize,
) -> Result<usize> {
    buf.reserve_spare(min_reserve);
    let dst = buf.spare_capacity_mut();
    let n = stream.read(dst).map_err(FalcornError::IoError)?;
    buf.advance_len(n);
    Ok(n)
}

async fn read_into_pooled_async<S: AsyncRead + Unpin>(
    stream: &mut S,
    buf: &mut PooledBuffer,
    min_reserve: usize,
) -> Result<usize> {
    buf.reserve_spare(min_reserve);
    let dst = buf.spare_capacity_mut();
    let n = stream.read(dst).await.map_err(FalcornError::IoError)?;
    buf.advance_len(n);
    Ok(n)
}

fn ensure_available_sync<S: Read>(
    stream: &mut S,
    buf: &mut PooledBuffer,
    needed: usize,
) -> Result<()> {
    while buf.buffer().len() < needed {
        let n = read_into_pooled_sync(stream, buf, needed - buf.buffer().len())?;
        if n == 0 {
            return Err(FalcornError::ConnectionError {
                reason: "Client closed connection".to_string(),
            });
        }
    }
    Ok(())
}

async fn ensure_available_async<S: AsyncRead + Unpin>(
    stream: &mut S,
    buf: &mut PooledBuffer,
    needed: usize,
    worker_timeout: u64,
) -> Result<()> {
    while buf.buffer().len() < needed {
        let n = timeout(
            Duration::from_secs(worker_timeout),
            read_into_pooled_async(stream, buf, needed - buf.buffer().len()),
        )
        .await
        .map_err(|_| FalcornError::RequestTimeout {
            seconds: worker_timeout,
        })??;
        if n == 0 {
            return Err(FalcornError::ConnectionError {
                reason: "Client closed connection".to_string(),
            });
        }
    }
    Ok(())
}

fn slice_range_for_header_value(data: &[u8], value: &[u8]) -> std::ops::Range<usize> {
    let start = value.as_ptr() as usize - data.as_ptr() as usize;
    let end = start + value.len();
    start..end
}
