//! Integration tests for the egress-governing reqwest middleware.

use klieo_bus_memory::MemoryBus;
use klieo_ops::governor::{governed_client, Governor, TokenBucketGovernor};
use klieo_ops::types::ProviderId;
use std::sync::Arc;
use wiremock::matchers::{method, path};
use wiremock::{Mock, MockServer, ResponseTemplate};

#[tokio::test]
async fn out_of_allowlist_host_is_rejected_preflight() {
    let bus = MemoryBus::new();
    let governor: Arc<dyn Governor> = Arc::new(
        TokenBucketGovernor::builder(bus.kv.clone())
            .llm_limit(ProviderId("noop".into()), 1)
            .build(),
    );
    let client = governed_client(governor, &["allowed.example"]).expect("build ok");
    let result = client.get("http://forbidden.example/x").send().await;
    assert!(result.is_err(), "out-of-allowlist host must error");
    let err = format!("{:?}", result.unwrap_err());
    assert!(
        err.contains("not in allowlist"),
        "error message must mention allowlist; got {err}"
    );
}

#[tokio::test]
async fn allowlisted_host_passes_through() {
    let server = MockServer::start().await;
    Mock::given(method("GET"))
        .and(path("/health"))
        .respond_with(ResponseTemplate::new(200).set_body_string("ok"))
        .mount(&server)
        .await;

    let server_uri = server.uri();
    // MockServer URI is "http://127.0.0.1:<port>" — extract the bare hostname
    // (no port, no scheme) to match what reqwest's `Url::host_str()` returns.
    let host = server_uri
        .strip_prefix("http://")
        .unwrap_or(&server_uri)
        .split(':')
        .next()
        .unwrap_or("127.0.0.1")
        .to_string();

    let bus = MemoryBus::new();
    let governor: Arc<dyn Governor> = Arc::new(
        TokenBucketGovernor::builder(bus.kv.clone())
            .llm_limit(ProviderId("noop".into()), 1)
            .egress_default_rps(100)
            .build(),
    );
    let client = governed_client(governor, &[host.as_str()]).expect("build ok");
    let resp = client
        .get(format!("{server_uri}/health"))
        .send()
        .await
        .expect("request ok");
    assert_eq!(resp.status().as_u16(), 200);
}
