//! Host-based client routing helpers.
//!
//! This module exposes wildcard host routing behavior through a stable facade
//! while internal concerns are split into focused modules:
//! - `config`: environment-driven routing configuration
//! - `host_pattern`: host normalization and prefix extraction rules
//! - `header_inference`: request-header inference and bypass policy

mod config;
mod header_inference;
mod host_pattern;

/// Default wildcard host pattern used when env override is absent.
pub const DEFAULT_WILDCARD_HOST_PATTERN: &str = athena_dns::DEFAULT_WILDCARD_HOST_PATTERN;
/// Default wildcard target base URL used by wildcard routing metadata.
pub const DEFAULT_WILDCARD_TARGET_BASE_URL: &str = athena_dns::DEFAULT_WILDCARD_TARGET_BASE_URL;
pub use athena_dns::PublicHostRoute;

pub use config::{wildcard_host_pattern, wildcard_host_routing_enabled};
pub use header_inference::{infer_wildcard_host_prefix, resolve_public_host_route};
pub use host_pattern::{build_host_from_prefix, extract_prefix_from_host, parse_public_host_route};

#[cfg(test)]
mod tests {
    use super::{
        build_host_from_prefix, extract_prefix_from_host, infer_wildcard_host_prefix,
        wildcard_host_pattern, wildcard_host_routing_enabled,
    };
    use actix_web::http::header::{FORWARDED, HOST, HeaderMap, HeaderName, HeaderValue};
    use std::sync::Mutex;

    static ENV_LOCK: Mutex<()> = Mutex::new(());

    const ENV_WILDCARD_HOST_PATTERN: &str = "ATHENA_WILDCARD_HOST_PATTERN";
    const ENV_WILDCARD_HOST_ROUTING_ENABLED: &str = "ATHENA_WILDCARD_HOST_ROUTING_ENABLED";
    const TEST_WILDCARD_HOST_PATTERN: &str = "*.v3.athena-cluster.com";

    fn with_env_var<T>(key: &str, value: Option<&str>, run: impl FnOnce() -> T) -> T {
        let original = std::env::var_os(key);
        match value {
            Some(value) => unsafe {
                std::env::set_var(key, value);
            },
            None => unsafe {
                std::env::remove_var(key);
            },
        }

        let result = run();

        match original {
            Some(value) => unsafe {
                std::env::set_var(key, value);
            },
            None => unsafe {
                std::env::remove_var(key);
            },
        }

        result
    }

    fn with_test_wildcard_host_env<T>(run: impl FnOnce() -> T) -> T {
        with_env_var(ENV_WILDCARD_HOST_ROUTING_ENABLED, Some("true"), || {
            with_env_var(
                ENV_WILDCARD_HOST_PATTERN,
                Some(TEST_WILDCARD_HOST_PATTERN),
                run,
            )
        })
    }

    #[test]
    fn extracts_prefix_from_matching_host() {
        let prefix = extract_prefix_from_host(
            "athena_logging.v3.athena-cluster.com",
            "*.v3.athena-cluster.com",
        );
        assert_eq!(prefix.as_deref(), Some("athena_logging"));
    }

    #[test]
    fn extracts_prefix_and_strips_port() {
        let prefix = extract_prefix_from_host(
            "Reporting.v3.athena-cluster.com:443",
            "*.v3.athena-cluster.com",
        );
        assert_eq!(prefix.as_deref(), Some("reporting"));
    }

    #[test]
    fn rejects_multi_label_prefix() {
        let prefix: Option<String> =
            extract_prefix_from_host("foo.bar.v3.athena-cluster.com", "*.v3.athena-cluster.com");
        assert!(prefix.is_none());
    }

    #[test]
    fn rejects_non_matching_suffix() {
        let prefix: Option<String> = extract_prefix_from_host(
            "athena_logging.v2.athena-cluster.com",
            "*.v3.athena-cluster.com",
        );
        assert!(prefix.is_none());
    }

    #[test]
    fn infer_skips_when_explicit_headers_exist() {
        let _guard: std::sync::MutexGuard<'_, ()> = ENV_LOCK.lock().expect("lock env mutex");
        let mut headers = HeaderMap::new();
        headers.insert(
            HOST,
            HeaderValue::from_static("athena_logging.v3.athena-cluster.com"),
        );
        headers.insert(
            HeaderName::from_static("x-athena-client"),
            HeaderValue::from_static("explicit"),
        );
        with_test_wildcard_host_env(|| {
            assert!(infer_wildcard_host_prefix(&headers).is_none());
        });
    }

    #[test]
    fn env_defaults_are_set() {
        let _guard = ENV_LOCK.lock().expect("lock env mutex");
        assert!(!wildcard_host_pattern().trim().is_empty());
        let _ = wildcard_host_routing_enabled();
    }

    #[test]
    fn extract_accepts_hyphen_underscore_and_digits() {
        let prefix: Option<String> = extract_prefix_from_host(
            "acme_42-prod.v3.athena-cluster.com",
            "*.v3.athena-cluster.com",
        );
        assert_eq!(prefix.as_deref(), Some("acme_42-prod"));
    }

    #[test]
    fn extract_lowercases_prefix() {
        let prefix: Option<String> =
            extract_prefix_from_host("AcMe_42.v3.athena-cluster.com", "*.v3.athena-cluster.com");
        assert_eq!(prefix.as_deref(), Some("acme_42"));
    }

    #[test]
    fn extract_rejects_empty_prefix() {
        let prefix: Option<String> =
            extract_prefix_from_host("v3.athena-cluster.com", "*.v3.athena-cluster.com");
        assert!(prefix.is_none());
    }

    #[test]
    fn extract_rejects_invalid_prefix_character() {
        let prefix: Option<String> =
            extract_prefix_from_host("acme!prod.v3.athena-cluster.com", "*.v3.athena-cluster.com");
        assert!(prefix.is_none());
    }

    #[test]
    fn extract_accepts_trailing_dot() {
        let prefix: Option<String> = extract_prefix_from_host(
            "athena_logging.v3.athena-cluster.com.",
            "*.v3.athena-cluster.com",
        );
        assert_eq!(prefix.as_deref(), Some("athena_logging"));
    }

    #[test]
    fn build_host_uses_wildcard_suffix() {
        let host: Option<String> = build_host_from_prefix("athena-clients", "*.athena-cluster.com");
        assert_eq!(host.as_deref(), Some("athena-clients.athena-cluster.com"));
    }

    #[test]
    fn extract_rejects_ipv6_host() {
        let prefix: Option<String> =
            extract_prefix_from_host("[::1]:4052", "*.v3.athena-cluster.com");
        assert!(prefix.is_none());
    }

    #[test]
    fn extract_rejects_invalid_wildcard_pattern() {
        let prefix: Option<String> = extract_prefix_from_host(
            "athena_logging.v3.athena-cluster.com",
            "*.*.athena-cluster.com",
        );
        assert!(prefix.is_none());
    }

    #[test]
    fn infer_returns_none_without_host_header() {
        let _guard: std::sync::MutexGuard<'_, ()> = ENV_LOCK.lock().expect("lock env mutex");
        let headers = HeaderMap::new();
        with_test_wildcard_host_env(|| {
            assert!(infer_wildcard_host_prefix(&headers).is_none());
        });
    }

    #[test]
    fn infer_skips_when_jdbc_header_exists() {
        let _guard: std::sync::MutexGuard<'_, ()> = ENV_LOCK.lock().expect("lock env mutex");
        let mut headers = HeaderMap::new();
        headers.insert(
            HOST,
            HeaderValue::from_static("athena_logging.v3.athena-cluster.com"),
        );
        headers.insert(
            HeaderName::from_static("x-jdbc-url"),
            HeaderValue::from_static("jdbc:postgresql://localhost:5432/db"),
        );
        with_test_wildcard_host_env(|| {
            assert!(infer_wildcard_host_prefix(&headers).is_none());
        });
    }

    #[test]
    fn infer_skips_when_x_pg_uri_header_exists() {
        let _guard: std::sync::MutexGuard<'_, ()> = ENV_LOCK.lock().expect("lock env mutex");
        let mut headers = HeaderMap::new();
        headers.insert(
            HOST,
            HeaderValue::from_static("athena_logging.v3.athena-cluster.com"),
        );
        headers.insert(
            HeaderName::from_static("x-pg-uri"),
            HeaderValue::from_static("postgres://user:pass@db.example.com:5432/db"),
        );
        with_test_wildcard_host_env(|| {
            assert!(infer_wildcard_host_prefix(&headers).is_none());
        });
    }

    #[test]
    fn infer_resolves_prefix_from_host_without_explicit_headers() {
        let _guard: std::sync::MutexGuard<'_, ()> = ENV_LOCK.lock().expect("lock env mutex");
        let mut headers = HeaderMap::new();
        headers.insert(
            HOST,
            HeaderValue::from_static("athena_logging.v3.athena-cluster.com"),
        );
        with_test_wildcard_host_env(|| {
            let prefix: Option<String> = infer_wildcard_host_prefix(&headers);
            assert_eq!(prefix.as_deref(), Some("athena_logging"));
        });
    }

    #[test]
    fn infer_resolves_prefix_from_host_with_port() {
        let _guard: std::sync::MutexGuard<'_, ()> = ENV_LOCK.lock().expect("lock env mutex");
        let mut headers = HeaderMap::new();
        headers.insert(
            HOST,
            HeaderValue::from_static("reporting.v3.athena-cluster.com:443"),
        );
        with_test_wildcard_host_env(|| {
            let prefix = infer_wildcard_host_prefix(&headers);
            assert_eq!(prefix.as_deref(), Some("reporting"));
        });
    }

    #[test]
    fn infer_resolves_prefix_from_x_forwarded_host_when_host_is_upstream() {
        let _guard: std::sync::MutexGuard<'_, ()> = ENV_LOCK.lock().expect("lock env mutex");
        let mut headers = HeaderMap::new();
        headers.insert(HOST, HeaderValue::from_static("internal-athena:5052"));
        headers.insert(
            HeaderName::from_static("x-forwarded-host"),
            HeaderValue::from_static("suits-formations.v3.athena-cluster.com"),
        );
        with_test_wildcard_host_env(|| {
            let prefix = infer_wildcard_host_prefix(&headers);
            assert_eq!(prefix.as_deref(), Some("suits-formations"));
        });
    }

    #[test]
    fn infer_resolves_prefix_from_forwarded_host_when_host_is_upstream() {
        let _guard: std::sync::MutexGuard<'_, ()> = ENV_LOCK.lock().expect("lock env mutex");
        let mut headers = HeaderMap::new();
        headers.insert(HOST, HeaderValue::from_static("internal-athena:5052"));
        headers.insert(
            FORWARDED,
            HeaderValue::from_static(
                r#"for=203.0.113.9;proto=https;host="suits-formations.v3.athena-cluster.com""#,
            ),
        );
        with_test_wildcard_host_env(|| {
            let prefix = infer_wildcard_host_prefix(&headers);
            assert_eq!(prefix.as_deref(), Some("suits-formations"));
        });
    }

    #[test]
    fn wildcard_host_pattern_uses_env_override() {
        let _guard = ENV_LOCK.lock().expect("lock env mutex");
        with_env_var(
            ENV_WILDCARD_HOST_PATTERN,
            Some("*.v4.athena-cluster.com"),
            || {
                assert_eq!(wildcard_host_pattern(), "*.v4.athena-cluster.com");
            },
        );
    }

    #[test]
    fn wildcard_host_routing_enabled_respects_false_values() {
        let _guard = ENV_LOCK.lock().expect("lock env mutex");
        for value in ["0", "false", "no", "off"] {
            with_env_var(ENV_WILDCARD_HOST_ROUTING_ENABLED, Some(value), || {
                assert!(
                    !wildcard_host_routing_enabled(),
                    "value '{value}' should disable"
                );
            });
        }
    }

    #[test]
    fn wildcard_host_routing_enabled_accepts_trueish_values() {
        let _guard = ENV_LOCK.lock().expect("lock env mutex");
        for value in ["1", "true", "yes", "on"] {
            with_env_var(ENV_WILDCARD_HOST_ROUTING_ENABLED, Some(value), || {
                assert!(
                    wildcard_host_routing_enabled(),
                    "value '{value}' should enable"
                );
            });
        }
    }
}
