#![allow(clippy::field_reassign_with_default)]
use super::Duration;
use super::http_transport::{HttpTransport, HttpTransportOptions};
use futures::StreamExt;
use secir::transport::{RequestPlan, RequestSpec, Transport};
use wiremock::matchers::{method, path};
use wiremock::{Mock, MockServer, ResponseTemplate};

#[tokio::test]
async fn test_redirects_false_returns_302_as_is() {
    let mock_server = MockServer::start().await;

    Mock::given(method("GET"))
        .and(path("/redirect"))
        .respond_with(ResponseTemplate::new(302).insert_header("Location", "/target"))
        .mount(&mock_server)
        .await;

    let mut opts = HttpTransportOptions::default();
    opts.allow_internal = true; // allow localhost for wiremock
    let transport =
        HttpTransport::with_transport_options(10, Duration::from_secs(10), opts).unwrap();

    let spec = RequestSpec {
        url: format!("{}/redirect", mock_server.uri()),
        method: "GET".to_string(),
        follow_redirects: false,
        max_redirects: 10,
        ..Default::default()
    };

    let plan = RequestPlan {
        requests: vec![spec],
        ..Default::default()
    };

    let mut stream = transport.execute(&plan);
    let resp: secir::Response = stream.next().await.unwrap().unwrap();

    assert_eq!(resp.data.status, 302);
}

#[tokio::test]
async fn test_max_redirects_stops_at_limit() {
    let mock_server = MockServer::start().await;

    Mock::given(method("GET"))
        .and(path("/loop"))
        .respond_with(ResponseTemplate::new(302).insert_header("Location", "/loop"))
        .mount(&mock_server)
        .await;

    let mut opts = HttpTransportOptions::default();
    opts.allow_internal = true;
    let transport =
        HttpTransport::with_transport_options(10, Duration::from_secs(10), opts).unwrap();

    let spec = RequestSpec {
        url: format!("{}/loop", mock_server.uri()),
        method: "GET".to_string(),
        follow_redirects: true,
        max_redirects: 2, // Should stop after 2 redirects
        ..Default::default()
    };

    let plan = RequestPlan {
        requests: vec![spec],
        ..Default::default()
    };

    let mut stream = transport.execute(&plan);
    let resp = stream.next().await.unwrap();

    // Stopping at the redirect cap returns the last redirect response instead of surfacing an error.
    let resp: secir::Response = resp.unwrap();
    assert_eq!(resp.data.status, 302);
}
