//! HTTP version detection helpers (TLS/ALPN + cleartext preface)

use super::types::HttpVersion;

const H2_PREFACE: &[u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";

pub fn looks_like_http2_preface(buf: &[u8]) -> bool {
    buf.len() >= H2_PREFACE.len() && &buf[..H2_PREFACE.len()] == H2_PREFACE
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PrefaceMatch {
    Full,
    Partial,
    None,
}

pub fn classify_http2_preface(buf: &[u8]) -> PrefaceMatch {
    if buf.is_empty() {
        return PrefaceMatch::None;
    }

    let len = buf.len().min(H2_PREFACE.len());
    if &buf[..len] != &H2_PREFACE[..len] {
        return PrefaceMatch::None;
    }

    if buf.len() >= H2_PREFACE.len() {
        PrefaceMatch::Full
    } else {
        PrefaceMatch::Partial
    }
}

pub fn detect_from_alpn(alpn: Option<&[u8]>) -> HttpVersion {
    match alpn {
        Some(b"h2") => HttpVersion::Http2,
        Some(b"http/1.0") => HttpVersion::Http10,
        Some(b"http/1.1") => HttpVersion::Http11,
        // Some stacks return b"http/1.1" when no ALPN negotiated.
        _ => HttpVersion::Http11,
    }
}

pub fn detect_from_preface(buf: &[u8]) -> HttpVersion {
    if looks_like_http2_preface(buf) {
        HttpVersion::Http2
    } else {
        HttpVersion::Http11
    }
}

// TESTS
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_looks_like_http2_preface() {
        let preface = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
        assert!(looks_like_http2_preface(preface));
        assert!(!looks_like_http2_preface(b"GET / HTTP/1.1\r\n"));
    }

    #[test]
    fn test_classify_http2_preface() {
        assert_eq!(classify_http2_preface(b""), PrefaceMatch::None);
        assert_eq!(classify_http2_preface(b"PRI * HT"), PrefaceMatch::Partial);
        assert_eq!(
            classify_http2_preface(b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"),
            PrefaceMatch::Full
        );
        assert_eq!(classify_http2_preface(b"GET /"), PrefaceMatch::None);
    }

    #[test]
    fn test_detect_from_alpn() {
        assert_eq!(detect_from_alpn(Some(b"h2")), HttpVersion::Http2);
        assert_eq!(detect_from_alpn(Some(b"http/1.0")), HttpVersion::Http10);
        assert_eq!(detect_from_alpn(Some(b"http/1.1")), HttpVersion::Http11);
        assert_eq!(detect_from_alpn(None), HttpVersion::Http11);
        assert_eq!(detect_from_alpn(Some(b"h3")), HttpVersion::Http11);
    }

    #[test]
    fn test_detect_from_preface() {
        let preface = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
        assert_eq!(detect_from_preface(preface), HttpVersion::Http2);
        assert_eq!(
            detect_from_preface(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n"),
            HttpVersion::Http11
        );
    }
}
