use lmrc_cloudflare::CloudflareClient;
use wiremock::matchers::{header, method, path, query_param};
use wiremock::{Mock, MockServer, ResponseTemplate};

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

    let response_body = r#"{
        "success": true,
        "errors": [],
        "messages": [],
        "result": [
            {
                "id": "zone1",
                "name": "example.com",
                "status": "active",
                "paused": false,
                "type": "full",
                "development_mode": 0,
                "name_servers": ["ns1.cloudflare.com", "ns2.cloudflare.com"]
            },
            {
                "id": "zone2",
                "name": "example.org",
                "status": "active",
                "paused": false,
                "type": "full",
                "development_mode": 0,
                "name_servers": ["ns1.cloudflare.com", "ns2.cloudflare.com"]
            }
        ]
    }"#;

    Mock::given(method("GET"))
        .and(path("/zones"))
        .and(header("authorization", "Bearer test-token"))
        .respond_with(ResponseTemplate::new(200).set_body_string(response_body))
        .mount(&mock_server)
        .await;

    let client = CloudflareClient::builder()
        .api_token("test-token")
        .base_url(mock_server.uri())
        .build()
        .unwrap();

    let zones = client.zones().list().send().await.unwrap();

    assert_eq!(zones.len(), 2);
    assert_eq!(zones[0].id, "zone1");
    assert_eq!(zones[0].name, "example.com");
    assert_eq!(zones[1].id, "zone2");
    assert_eq!(zones[1].name, "example.org");
}

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

    let response_body = r#"{
        "success": true,
        "errors": [],
        "messages": [],
        "result": [
            {
                "id": "zone1",
                "name": "example.com",
                "status": "active",
                "paused": false,
                "type": "full",
                "development_mode": 0,
                "name_servers": ["ns1.cloudflare.com"]
            }
        ]
    }"#;

    Mock::given(method("GET"))
        .and(path("/zones"))
        .and(query_param("name", "example.com"))
        .respond_with(ResponseTemplate::new(200).set_body_string(response_body))
        .mount(&mock_server)
        .await;

    let client = CloudflareClient::builder()
        .api_token("test-token")
        .base_url(mock_server.uri())
        .build()
        .unwrap();

    let zones = client
        .zones()
        .list()
        .name("example.com")
        .send()
        .await
        .unwrap();

    assert_eq!(zones.len(), 1);
    assert_eq!(zones[0].name, "example.com");
}

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

    let response_body = r#"{
        "success": true,
        "errors": [],
        "messages": [],
        "result": []
    }"#;

    Mock::given(method("GET"))
        .and(path("/zones"))
        .and(query_param("status", "pending"))
        .respond_with(ResponseTemplate::new(200).set_body_string(response_body))
        .mount(&mock_server)
        .await;

    let client = CloudflareClient::builder()
        .api_token("test-token")
        .base_url(mock_server.uri())
        .build()
        .unwrap();

    let zones = client
        .zones()
        .list()
        .status("pending")
        .send()
        .await
        .unwrap();

    assert_eq!(zones.len(), 0);
}

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

    let response_body = r#"{
        "success": true,
        "errors": [],
        "messages": [],
        "result": [
            {
                "id": "zone1",
                "name": "example.com",
                "status": "active",
                "paused": false,
                "type": "full",
                "development_mode": 0,
                "name_servers": ["ns1.cloudflare.com"]
            }
        ]
    }"#;

    Mock::given(method("GET"))
        .and(path("/zones"))
        .and(query_param("page", "2"))
        .and(query_param("per_page", "50"))
        .respond_with(ResponseTemplate::new(200).set_body_string(response_body))
        .mount(&mock_server)
        .await;

    let client = CloudflareClient::builder()
        .api_token("test-token")
        .base_url(mock_server.uri())
        .build()
        .unwrap();

    let _zones = client
        .zones()
        .list()
        .page(2)
        .per_page(50)
        .send()
        .await
        .unwrap();
}

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

    let response_body = r#"{
        "success": true,
        "errors": [],
        "messages": [],
        "result": {
            "id": "zone123",
            "name": "example.com",
            "status": "active",
            "paused": false,
            "type": "full",
                "development_mode": 0,
            "name_servers": ["ns1.cloudflare.com", "ns2.cloudflare.com"]
        }
    }"#;

    Mock::given(method("GET"))
        .and(path("/zones/zone123"))
        .respond_with(ResponseTemplate::new(200).set_body_string(response_body))
        .mount(&mock_server)
        .await;

    let client = CloudflareClient::builder()
        .api_token("test-token")
        .base_url(mock_server.uri())
        .build()
        .unwrap();

    let zone = client.zones().get("zone123").await.unwrap();

    assert_eq!(zone.id, "zone123");
    assert_eq!(zone.name, "example.com");
    assert_eq!(zone.status, "active");
}

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

    let response_body = r#"{
        "success": true,
        "errors": [],
        "messages": [],
        "result": [
            {
                "id": "zone123",
                "name": "example.com",
                "status": "active",
                "paused": false,
                "type": "full",
                "development_mode": 0,
                "name_servers": ["ns1.cloudflare.com"]
            }
        ]
    }"#;

    Mock::given(method("GET"))
        .and(path("/zones"))
        .and(query_param("name", "example.com"))
        .respond_with(ResponseTemplate::new(200).set_body_string(response_body))
        .mount(&mock_server)
        .await;

    let client = CloudflareClient::builder()
        .api_token("test-token")
        .base_url(mock_server.uri())
        .build()
        .unwrap();

    let zone = client
        .zones()
        .find_by_name("example.com")
        .await
        .unwrap()
        .unwrap();

    assert_eq!(zone.id, "zone123");
    assert_eq!(zone.name, "example.com");
}

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

    let response_body = r#"{
        "success": true,
        "errors": [],
        "messages": [],
        "result": [
            {
                "id": "zone123",
                "name": "example.com",
                "status": "active",
                "paused": false,
                "type": "full",
                "development_mode": 0,
                "name_servers": ["ns1.cloudflare.com"]
            }
        ]
    }"#;

    Mock::given(method("GET"))
        .and(path("/zones"))
        .and(query_param("name", "example.com"))
        .respond_with(ResponseTemplate::new(200).set_body_string(response_body))
        .mount(&mock_server)
        .await;

    let client = CloudflareClient::builder()
        .api_token("test-token")
        .base_url(mock_server.uri())
        .build()
        .unwrap();

    let zone_id = client.zones().get_zone_id("example.com").await.unwrap();

    assert_eq!(zone_id, "zone123");
}

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

    let response_body = r#"{
        "success": true,
        "errors": [],
        "messages": [],
        "result": []
    }"#;

    Mock::given(method("GET"))
        .and(path("/zones"))
        .and(query_param("name", "nonexistent.com"))
        .respond_with(ResponseTemplate::new(200).set_body_string(response_body))
        .mount(&mock_server)
        .await;

    let client = CloudflareClient::builder()
        .api_token("test-token")
        .base_url(mock_server.uri())
        .build()
        .unwrap();

    let result = client
        .zones()
        .find_by_name("nonexistent.com")
        .await
        .unwrap();

    assert!(result.is_none());
}
