use super::*;
use reqwest::StatusCode;
use reqwest::header::{HeaderMap, HeaderName, HeaderValue};

#[test]
fn test_status_checks() {
    let resp = ScanResponse::from_parts(StatusCode::OK, HeaderMap::new(), vec![]);
    assert_eq!(resp.status(), StatusCode::OK);

    let resp2 = ScanResponse::from_parts(StatusCode::NOT_FOUND, HeaderMap::new(), vec![]);
    assert_eq!(resp2.status(), StatusCode::NOT_FOUND);
}

#[test]
fn test_header_extraction() {
    let mut headers = HeaderMap::new();
    headers.insert(
        HeaderName::from_static("x-custom-test"),
        HeaderValue::from_static("test-value"),
    );
    headers.insert(
        HeaderName::from_static("content-type"),
        HeaderValue::from_static("application/json"),
    );

    let resp = ScanResponse::from_parts(StatusCode::OK, headers.clone(), vec![]);

    assert_eq!(resp.headers(), &headers);
    assert_eq!(resp.header_value("x-custom-test"), Some("test-value"));
    assert_eq!(resp.header_value("content-type"), Some("application/json"));
    assert_eq!(resp.header_value("non-existent"), None);
}

#[test]
fn test_body_methods() {
    let body = b"hello world".to_vec();
    let resp = ScanResponse::from_parts(StatusCode::OK, HeaderMap::new(), body.clone());

    assert_eq!(resp.body_bytes(), b"hello world");
    assert_eq!(resp.body_text().unwrap(), "hello world");
    assert!(resp.contains("hello"));
    assert!(!resp.contains("goodbye"));
}

#[test]
fn test_body_contains_lossy_utf8() {
    let mut body = b"hello ".to_vec();
    body.push(0xff); // invalid utf-8
    body.extend_from_slice(b" world");

    let resp = ScanResponse::from_parts(StatusCode::OK, HeaderMap::new(), body);

    assert!(resp.body_text().is_err());
    assert!(resp.contains("hello"));
    assert!(resp.contains("world"));
}

#[test]
fn body_text_empty_body_is_ok() {
    let resp = ScanResponse::from_parts(StatusCode::NO_CONTENT, HeaderMap::new(), vec![]);
    assert_eq!(resp.body_text().unwrap(), "");
    assert!(!resp.contains("anything"));
}

#[test]
fn body_text_handles_null_bytes() {
    let body = b"ab\0cd".to_vec();
    let resp = ScanResponse::from_parts(StatusCode::OK, HeaderMap::new(), body);
    let text = resp.body_text().unwrap();
    assert_eq!(text.len(), 5);
    assert!(resp.contains("ab"));
    assert!(resp.contains("cd"));
}

#[test]
fn contains_handles_unicode_needles() {
    let body = "hello 世界 and Привет".as_bytes().to_vec();
    let resp = ScanResponse::from_parts(StatusCode::OK, HeaderMap::new(), body);
    assert!(resp.contains("世界"));
    assert!(resp.contains("Привет"));
    assert!(!resp.contains("不存在"));
}

#[test]
fn header_value_invalid_header_name_returns_none() {
    let resp = ScanResponse::from_parts(StatusCode::OK, HeaderMap::new(), vec![]);
    assert_eq!(resp.header_value("bad\nheader"), None);
}

#[test]
fn header_value_non_utf8_header_returns_none() {
    let mut headers = HeaderMap::new();
    headers.insert(
        HeaderName::from_static("x-bin"),
        HeaderValue::from_bytes(&[0x66, 0x6f, 0x80, 0x6f]).unwrap(),
    );
    let resp = ScanResponse::from_parts(StatusCode::OK, headers, vec![]);
    assert_eq!(resp.header_value("x-bin"), None);
}

#[test]
fn from_parts_with_huge_body_is_accessible() {
    let body = vec![b'A'; 2 * 1024 * 1024];
    let resp = ScanResponse::from_parts(StatusCode::OK, HeaderMap::new(), body);
    assert_eq!(resp.body_bytes().len(), 2 * 1024 * 1024);
    assert_eq!(resp.status(), StatusCode::OK);
}

#[test]
fn headers_reference_matches_inserted_values() {
    let mut headers = HeaderMap::new();
    headers.insert("x-a", HeaderValue::from_static("1"));
    headers.insert("x-b", HeaderValue::from_static("2"));
    let resp = ScanResponse::from_parts(StatusCode::OK, headers, vec![]);
    assert_eq!(resp.headers().len(), 2);
    assert_eq!(resp.header_value("x-a"), Some("1"));
    assert_eq!(resp.header_value("x-b"), Some("2"));
}
