use anycms_core::{ApiResult, ErrorCode, FieldError, ResponseData, ResultPagination};
use serde::Serialize;
use serde_json::json;

#[derive(Debug, Serialize, PartialEq)]
struct User {
    id: u32,
    name: String,
}

#[test]
fn test_single_value_serialization() {
    let user = User {
        id: 1,
        name: "Alice".to_string(),
    };

    let result: ApiResult<User> = ApiResult::value(user);

    let json = serde_json::to_value(&result).unwrap();
    let expected = json!({
        "success": true,
        "data": {
            "id": 1,
            "name": "Alice"
        }
    });

    assert_eq!(json, expected);
}

#[test]
fn test_list_serialization() {
    let users = vec![
        User {
            id: 1,
            name: "Alice".to_string(),
        },
        User {
            id: 2,
            name: "Bob".to_string(),
        },
    ];

    let pagination = ResultPagination::new(100, 1, 10);
    let result: ApiResult<User> = ApiResult::list(users).with_pagination(pagination);

    let json = serde_json::to_value(&result).unwrap();

    // Verify common fields
    assert_eq!(json["success"], true);
    assert_eq!(json["data"][0]["id"], 1);
    assert_eq!(json["data"][1]["id"], 2);
    assert_eq!(json["pagination"]["total"], 100);
    assert_eq!(json["pagination"]["page"], 1);

    // Verify style-dependent field names
    #[cfg(not(feature = "snake-case"))]
    {
        assert_eq!(json["pagination"]["pageSize"], 10);
        assert_eq!(json["pagination"]["totalPages"], 10);
        assert_eq!(json["pagination"]["hasNextPage"], true);
        assert_eq!(json["pagination"]["hasPrevPage"], false);
    }
    #[cfg(feature = "snake-case")]
    {
        assert_eq!(json["pagination"]["page_size"], 10);
        assert_eq!(json["pagination"]["total_pages"], 10);
        assert_eq!(json["pagination"]["has_next_page"], true);
        assert_eq!(json["pagination"]["has_prev_page"], false);
    }
}

#[test]
fn test_pagination_helpers() {
    let p = ResultPagination::new(95, 3, 10);
    assert_eq!(p.total_pages(), 10);
    assert_eq!(p.total_pages, 10);
    assert!(p.has_next());
    assert!(p.has_next_page);
    assert!(p.has_prev());
    assert!(p.has_prev_page);

    let p_last = ResultPagination::new(95, 10, 10);
    assert!(!p_last.has_next());
    assert!(!p_last.has_next_page);

    let p_first = ResultPagination::new(95, 1, 10);
    assert!(!p_first.has_prev());
    assert!(!p_first.has_prev_page);
}

#[test]
fn test_empty_success() {
    let result: ApiResult<()> = ApiResult::ok();

    let json = serde_json::to_value(&result).unwrap();
    let expected = json!({
        "success": true
    });

    assert_eq!(json, expected);
}

#[test]
fn test_error_response() {
    let result: ApiResult<User> = ApiResult::fail("User not found").with_code(404);

    let json = serde_json::to_value(&result).unwrap();
    let expected = json!({
        "success": false,
        "message": "User not found",
        "code": 404
    });

    assert_eq!(json, expected);
}

#[test]
fn test_response_data_single() {
    let user = User {
        id: 1,
        name: "Alice".to_string(),
    };

    let data = ResponseData::single(user);
    let json = serde_json::to_value(&data).unwrap();

    let expected = json!({
        "id": 1,
        "name": "Alice"
    });

    assert_eq!(json, expected);
    assert!(data.is_single());
    assert!(!data.is_multiple());
}

#[test]
fn test_response_data_multiple() {
    let users = vec![
        User {
            id: 1,
            name: "Alice".to_string(),
        },
        User {
            id: 2,
            name: "Bob".to_string(),
        },
    ];

    let data = ResponseData::multiple(users);
    let json = serde_json::to_value(&data).unwrap();

    let expected = json!([
        { "id": 1, "name": "Alice" },
        { "id": 2, "name": "Bob" }
    ]);

    assert_eq!(json, expected);
    assert!(!data.is_single());
    assert!(data.is_multiple());
}

#[test]
fn test_with_extra() {
    let user = User {
        id: 1,
        name: "Alice".to_string(),
    };

    let result: ApiResult<User> = ApiResult::value(user)
        .with_extra("timestamp", serde_json::json!(1234567890))
        .with_extra("version", serde_json::json!("1.0.0"));

    let json = serde_json::to_value(&result).unwrap();
    let expected = json!({
        "success": true,
        "data": {
            "id": 1,
            "name": "Alice"
        },
        "extra": {
            "timestamp": 1234567890,
            "version": "1.0.0"
        }
    });

    assert_eq!(json, expected);
}

#[test]
fn test_from_result() {
    let ok: Result<String, &str> = Ok("hello".to_string());
    let result: ApiResult<String> = ApiResult::from_result(ok);
    assert!(result.success);
    assert!(result.data.unwrap().is_single());

    let err: Result<String, &str> = Err("something failed");
    let result: ApiResult<String> = ApiResult::from_result(err);
    assert!(!result.success);
    assert_eq!(result.code.unwrap(), 500);
}

#[test]
fn test_validation_errors() {
    let result: ApiResult<User> = ApiResult::validation_errors(vec![
        FieldError::new("email", "invalid format"),
        FieldError::new("name", "required"),
    ]);

    assert!(!result.success);
    assert_eq!(result.code.unwrap(), 422);
    assert_eq!(result.message.as_ref().unwrap(), "Validation failed");

    let json = serde_json::to_value(&result).unwrap();
    let expected = json!({
        "success": false,
        "message": "Validation failed",
        "code": 422,
        "errors": [
            { "field": "email", "message": "invalid format" },
            { "field": "name", "message": "required" }
        ]
    });
    assert_eq!(json, expected);
}

#[test]
fn test_with_error_builder() {
    let result: ApiResult<User> = ApiResult::fail("Validation failed")
        .with_code(422)
        .with_error("email", "invalid format")
        .with_error("name", "required");

    let errors = result.errors.unwrap();
    assert_eq!(errors.len(), 2);
    assert_eq!(errors[0].field, "email");
    assert_eq!(errors[1].field, "name");
}

#[test]
fn test_trace_id() {
    let result: ApiResult<User> = ApiResult::fail("Not found")
        .with_code(404)
        .with_trace_id("req-abc123");

    assert_eq!(result.trace_id.as_ref().unwrap(), "req-abc123");

    let json = serde_json::to_value(&result).unwrap();

    #[cfg(not(feature = "snake-case"))]
    assert_eq!(json["traceId"], "req-abc123");
    #[cfg(feature = "snake-case")]
    assert_eq!(json["trace_id"], "req-abc123");

    // success response without trace_id should not include the field
    let ok_result: ApiResult<()> = ApiResult::ok();
    let ok_json = serde_json::to_value(&ok_result).unwrap();
    assert!(ok_json.get("traceId").is_none());
}

#[test]
fn test_response_data_from_single() {
    let user = User {
        id: 1,
        name: "Alice".to_string(),
    };
    let data: ResponseData<User> = user.into();
    assert!(data.is_single());
}

#[test]
fn test_response_data_from_vec() {
    let users = vec![User {
        id: 1,
        name: "Alice".to_string(),
    }];
    let data: ResponseData<User> = users.into();
    assert!(data.is_multiple());
}

#[test]
fn test_biz_code() {
    let result: ApiResult<User> = ApiResult::fail("用户不存在")
        .with_code(404)
        .with_biz_code(10001);

    assert_eq!(result.biz_code, Some(10001));

    let json = serde_json::to_value(&result).unwrap();

    #[cfg(not(feature = "snake-case"))]
    assert_eq!(json["bizCode"], 10001);
    #[cfg(feature = "snake-case")]
    assert_eq!(json["biz_code"], 10001);
}

#[test]
fn test_timestamp() {
    let result: ApiResult<User> = ApiResult::ok().with_timestamp(1700000000000i64);

    assert_eq!(result.timestamp, Some(1700000000000));

    let json = serde_json::to_value(&result).unwrap();
    assert_eq!(json["timestamp"], 1700000000000i64);
}

#[test]
fn test_with_current_timestamp() {
    let result: ApiResult<()> = ApiResult::ok().with_current_timestamp();

    assert!(result.timestamp.is_some());
    let ts = result.timestamp.unwrap();
    // 应该是毫秒级时间戳，大于一个合理的值
    assert!(ts > 1000000000000); // after 2001-09-09
}

#[test]
fn test_from_io_error() {
    let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
    let result: ApiResult<String> = io_err.into();

    assert!(!result.success);
    assert_eq!(result.code, Some(500)); // InternalError
}

#[test]
fn test_response_data_empty() {
    let data: ResponseData<User> = ResponseData::Empty;
    assert!(data.is_empty());
    assert!(!data.is_single());
    assert!(!data.is_multiple());

    // Empty 序列化为 null
    let json = serde_json::to_value(&data).unwrap();
    assert!(json.is_null());
}

// ============================================================
// ResultPagination new methods
// ============================================================

#[test]
fn test_pagination_offset_limit() {
    let p = ResultPagination::new(100, 3, 10);
    assert_eq!(p.offset(), 20);
    assert_eq!(p.limit(), 10);

    // Page 1 => offset 0
    let p1 = ResultPagination::new(50, 1, 25);
    assert_eq!(p1.offset(), 0);
    assert_eq!(p1.limit(), 25);

    // Page 5, page_size 20 => offset 80
    let p5 = ResultPagination::new(200, 5, 20);
    assert_eq!(p5.offset(), 80);
    assert_eq!(p5.limit(), 20);
}

#[test]
fn test_pagination_first_last_page() {
    let p_first = ResultPagination::new(100, 1, 10);
    assert!(p_first.is_first_page());
    assert!(!p_first.is_last_page());

    let p_mid = ResultPagination::new(100, 5, 10);
    assert!(!p_mid.is_first_page());
    assert!(!p_mid.is_last_page());

    let p_last = ResultPagination::new(100, 10, 10);
    assert!(!p_last.is_first_page());
    assert!(p_last.is_last_page());

    // Single page: both first and last
    let p_single = ResultPagination::new(5, 1, 10);
    assert!(p_single.is_first_page());
    assert!(p_single.is_last_page());
}

#[test]
fn test_pagination_next_prev_page() {
    let p = ResultPagination::new(100, 3, 10);
    assert_eq!(p.next_page(), Some(4));
    assert_eq!(p.prev_page(), Some(2));

    // First page: no prev
    let p_first = ResultPagination::new(100, 1, 10);
    assert_eq!(p_first.next_page(), Some(2));
    assert_eq!(p_first.prev_page(), None);

    // Last page: no next
    let p_last = ResultPagination::new(100, 10, 10);
    assert_eq!(p_last.next_page(), None);
    assert_eq!(p_last.prev_page(), Some(9));

    // Single page: neither next nor prev
    let p_single = ResultPagination::new(3, 1, 10);
    assert_eq!(p_single.next_page(), None);
    assert_eq!(p_single.prev_page(), None);
}

#[test]
fn test_pagination_default() {
    let p = ResultPagination::default();
    assert_eq!(p.page, 1);
    assert_eq!(p.total, 0);
    assert_eq!(p.page_size, 10);
}

#[test]
fn test_pagination_equality() {
    let p1 = ResultPagination::new(100, 2, 10);
    let p2 = ResultPagination::new(100, 2, 10);
    assert_eq!(p1, p2);

    let p3 = ResultPagination::new(100, 3, 10);
    assert_ne!(p1, p3);
}

// ============================================================
// ResponseData new features
// ============================================================

#[test]
fn test_response_data_default() {
    let data: ResponseData<User> = ResponseData::default();
    assert!(data.is_empty());
}

#[test]
fn test_response_data_len() {
    let single = ResponseData::single(User {
        id: 1,
        name: "Alice".to_string(),
    });
    assert_eq!(single.len(), 1);

    let multiple = ResponseData::multiple(vec![
        User {
            id: 1,
            name: "Alice".to_string(),
        },
        User {
            id: 2,
            name: "Bob".to_string(),
        },
    ]);
    assert_eq!(multiple.len(), 2);

    let empty: ResponseData<User> = ResponseData::Empty;
    assert_eq!(empty.len(), 0);
}

#[test]
fn test_response_data_is_empty_data() {
    // Empty variant
    let empty: ResponseData<User> = ResponseData::Empty;
    assert!(empty.is_empty_data());
    assert!(empty.is_empty());

    // Multiple with empty vec: is_empty_data == true but is_empty == false
    let empty_vec: ResponseData<User> = ResponseData::multiple(vec![]);
    assert!(empty_vec.is_empty_data());
    assert!(!empty_vec.is_empty());

    // Non-empty variants
    let single = ResponseData::single(User {
        id: 1,
        name: "A".to_string(),
    });
    assert!(!single.is_empty_data());

    let multiple = ResponseData::multiple(vec![User {
        id: 1,
        name: "A".to_string(),
    }]);
    assert!(!multiple.is_empty_data());
}

// ============================================================
// ApiResult convenience methods
// ============================================================

#[test]
fn test_api_result_is_success_is_error() {
    let ok: ApiResult<User> = ApiResult::ok();
    assert!(ok.is_success());
    assert!(!ok.is_error());

    let value = ApiResult::value(User {
        id: 1,
        name: "Alice".to_string(),
    });
    assert!(value.is_success());
    assert!(!value.is_error());

    let fail: ApiResult<User> = ApiResult::fail("something went wrong");
    assert!(!fail.is_success());
    assert!(fail.is_error());
}

#[test]
fn test_api_result_error_code() {
    // Error returns Some
    let fail: ApiResult<User> = ApiResult::fail("not found").with_code(404);
    assert_eq!(fail.error_code(), Some(ErrorCode::NotFound));

    let fail500: ApiResult<User> = ApiResult::fail("internal").with_code(500);
    assert_eq!(fail500.error_code(), Some(ErrorCode::InternalError));

    // Success returns None
    let ok: ApiResult<User> = ApiResult::ok();
    assert_eq!(ok.error_code(), None);

    let value = ApiResult::value(User {
        id: 1,
        name: "Alice".to_string(),
    });
    assert_eq!(value.error_code(), None);
}
