//! Basic HTTP caching with surf
//!
//! Run with: cargo run --example surf_basic --features manager-cacache
//!
//! This example runs the surf middleware inside a tokio runtime so that
//! `CACacheManager` (which delegates to `cacache` compiled with its
//! `tokio-runtime` feature) has a reactor available for its internal
//! `tokio::fs` operations. Surf is runtime-agnostic when using the
//! `curl-client` backend (curl maintains its own I/O thread), so running
//! it inside tokio works fine.

use http_cache::{CacheMode, HttpCache, HttpCacheOptions};
use http_cache_surf::{CACacheManager, Cache};
use std::time::Instant;
use surf::Client;
use wiremock::{matchers::method, Mock, MockServer, ResponseTemplate};

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    // Setup mock server with cacheable response
    let mock_server = MockServer::start().await;
    Mock::given(method("GET"))
        .respond_with(
            ResponseTemplate::new(200)
                .set_body_string("Hello from cached response!")
                .append_header("cache-control", "max-age=300, public")
                .append_header("content-type", "text/plain"),
        )
        .mount(&mock_server)
        .await;

    let cache_dir = tempfile::tempdir().unwrap();
    let cache_manager =
        CACacheManager::new(cache_dir.path().to_path_buf(), true);
    let client = Client::new().with(Cache(HttpCache {
        mode: CacheMode::Default,
        manager: cache_manager,
        options: HttpCacheOptions::default(),
    }));

    let url = format!("{}/", mock_server.uri());

    println!("Testing HTTP caching with surf...");

    // First request
    let start = Instant::now();
    let response = client.get(&url).await?;

    println!("First request: {:?}", start.elapsed());
    println!("Status: {}", response.status());

    // Check cache headers after first request
    if let Some(x_cache) = response.header("x-cache") {
        println!("Cache header x-cache: {}", x_cache.as_str());
    }
    if let Some(x_cache_lookup) = response.header("x-cache-lookup") {
        println!("Cache header x-cache-lookup: {}", x_cache_lookup.as_str());
    }

    println!();

    // Second request
    let start = Instant::now();
    let response = client.get(&url).await?;

    println!("Second request: {:?}", start.elapsed());
    println!("Status: {}", response.status());

    // Check cache headers after second request
    if let Some(x_cache) = response.header("x-cache") {
        println!("Cache header x-cache: {}", x_cache.as_str());
    }
    if let Some(x_cache_lookup) = response.header("x-cache-lookup") {
        println!("Cache header x-cache-lookup: {}", x_cache_lookup.as_str());
    }

    Ok(())
}
