mod common;

use common::mock_client;
use ticksupply::Error;
use wiremock::matchers::{header, method, path};
use wiremock::{Mock, ResponseTemplate};

#[tokio::test]
async fn maps_not_found_and_captures_request_id() {
    let (server, client) = mock_client().await;

    Mock::given(method("GET"))
        .and(path("/v1/exchanges"))
        .and(header("X-Api-Key", "key_test.secret"))
        .respond_with(
            ResponseTemplate::new(404)
                .insert_header("X-Request-Id", "req_abc")
                .set_body_json(serde_json::json!({
                    "error": { "code": "not_found", "message": "gone" }
                })),
        )
        .mount(&server)
        .await;

    let err = client.exchanges().list().await.unwrap_err();
    match err {
        Error::NotFound {
            message,
            request_id,
        } => {
            assert_eq!(message, "gone");
            assert_eq!(request_id.as_deref(), Some("req_abc"));
        }
        other => panic!("wrong variant: {other:?}"),
    }
}

#[tokio::test]
async fn unknown_error_code_falls_through_to_api_variant() {
    let (server, client) = mock_client().await;

    Mock::given(method("GET"))
        .and(path("/v1/exchanges"))
        .respond_with(ResponseTemplate::new(418).set_body_json(serde_json::json!({
            "error": { "code": "teapot", "message": "short and stout" }
        })))
        .mount(&server)
        .await;

    let err = client.exchanges().list().await.unwrap_err();
    match err {
        Error::Api { code, status, .. } => {
            assert_eq!(code, "teapot");
            assert_eq!(status, 418);
        }
        other => panic!("wrong variant: {other:?}"),
    }
}

#[tokio::test]
async fn non_json_body_becomes_api_variant_with_message() {
    let (server, client) = mock_client().await;

    Mock::given(method("GET"))
        .and(path("/v1/exchanges"))
        .respond_with(ResponseTemplate::new(502).set_body_string("<html>Bad Gateway</html>"))
        .mount(&server)
        .await;

    let err = client.exchanges().list().await.unwrap_err();
    match err {
        Error::Api {
            code,
            status,
            message,
            ..
        } => {
            assert_eq!(code, "unknown");
            assert_eq!(status, 502);
            assert!(message.contains("Bad Gateway"));
        }
        other => panic!("wrong variant: {other:?}"),
    }
}
