//! Upgrade detection logic
//!
//! Provides unified detection for protocol upgrades (WebSocket, SSE) based on
//! request headers. This eliminates duplicate upgrade logic and enables
//! automatic protocol detection.
//!
//! # Examples
//!
//! ```rust,ignore
//! use ruxno::upgrade::{UpgradeDetector, UpgradeType};
//! use ruxno::domain::Request;
//!
//! // Detect upgrade type
//! match UpgradeDetector::detect(&request) {
//!     Some(UpgradeType::WebSocket) => println!("WebSocket upgrade detected"),
//!     Some(UpgradeType::SSE) => println!("SSE upgrade detected"),
//!     None => println!("Regular HTTP request"),
//! }
//!
//! // Check specific upgrade types
//! if UpgradeDetector::is_websocket(&request) {
//!     println!("WebSocket upgrade");
//! }
//!
//! if UpgradeDetector::is_sse(&request) {
//!     println!("SSE request");
//! }
//! ```

use crate::domain::Request;
use crate::upgrade::UpgradeType;

/// Check if a raw `http::HeaderMap` contains a valid WebSocket upgrade.
///
/// This is the low-level primitive used by both `UpgradeDetector` (domain layer)
/// and `RuxnoService` (server layer, which operates on hyper requests before
/// domain conversion). Both call this function so the logic lives in one place.
pub(crate) fn is_websocket_upgrade_headers(headers: &http::HeaderMap) -> bool {
    let has_upgrade = headers
        .get("upgrade")
        .and_then(|v| v.to_str().ok())
        .map(|v| v.to_lowercase() == "websocket")
        .unwrap_or(false);
    let has_key = headers.get("sec-websocket-key").is_some();
    has_upgrade && has_key
}

/// Upgrade detector
///
/// Provides methods to detect protocol upgrades from HTTP requests.
/// Supports WebSocket and Server-Sent Events (SSE) detection.
///
/// # Design
///
/// Uses a zero-sized struct with static methods for stateless detection.
/// All detection logic is based on HTTP headers following RFC specifications.
pub struct UpgradeDetector;

impl UpgradeDetector {
    /// Detect upgrade type from request headers
    ///
    /// Returns `Some(UpgradeType)` if the request is a valid upgrade request,
    /// or `None` if it's a regular HTTP request.
    ///
    /// # Detection Priority
    ///
    /// 1. WebSocket - Checked first (requires explicit upgrade)
    /// 2. SSE - Checked second (content negotiation)
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// use ruxno::upgrade::{UpgradeDetector, UpgradeType};
    ///
    /// // WebSocket request
    /// assert_eq!(
    ///     UpgradeDetector::detect(&ws_request),
    ///     Some(UpgradeType::WebSocket)
    /// );
    ///
    /// // SSE request
    /// assert_eq!(
    ///     UpgradeDetector::detect(&sse_request),
    ///     Some(UpgradeType::SSE)
    /// );
    ///
    /// // Regular HTTP request
    /// assert_eq!(UpgradeDetector::detect(&http_request), None);
    /// ```
    pub fn detect(req: &Request) -> Option<UpgradeType> {
        // Check for WebSocket upgrade first (explicit upgrade)
        if Self::is_websocket(req) {
            return Some(UpgradeType::WebSocket);
        }

        // Check for SSE (content negotiation)
        if Self::is_sse(req) {
            return Some(UpgradeType::SSE);
        }

        None
    }

    /// Check if request is a WebSocket upgrade
    ///
    /// WebSocket upgrade requires:
    /// - `Upgrade: websocket` header (case-insensitive)
    /// - `Sec-WebSocket-Key` header (must be present)
    pub fn is_websocket(req: &Request) -> bool {
        is_websocket_upgrade_headers(req.headers().as_header_map())
    }

    /// Check if request is a Server-Sent Events (SSE) request
    ///
    /// SSE detection requires:
    /// - `Accept: text/event-stream` header (can be part of Accept list)
    ///
    /// # SSE Protocol
    ///
    /// SSE uses content negotiation via the Accept header.
    /// The client indicates it can accept `text/event-stream` responses.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// use ruxno::upgrade::UpgradeDetector;
    ///
    /// // Valid SSE request
    /// assert!(UpgradeDetector::is_sse(&sse_request));
    ///
    /// // Regular HTTP request
    /// assert!(!UpgradeDetector::is_sse(&http_request));
    /// ```
    pub fn is_sse(req: &Request) -> bool {
        // Check for "Accept: text/event-stream" header
        // Can be part of a comma-separated list (e.g., "text/event-stream, text/html")
        req.headers()
            .get("accept")
            .map(|v| v.contains("text/event-stream"))
            .unwrap_or(false)
    }
}
