// Copyright (c) Subzero Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

//! Types for the `getAllAccounts` RPC method.
//!
//! # ⚠️ WARNING: TEST INFRASTRUCTURE ONLY - DO NOT USE IN PRODUCTION ⚠️
//!
//! This method returns all accounts in the system. It is intended **exclusively**
//! for stress testing and debugging purposes within the onebox test environment.
//!
//! **This RPC method:**
//! - Is gated behind the `onebox-stress-test-only-do-not-use-otherwise` feature flag
//! - Should NEVER be enabled in production deployments
//! - Can be extremely expensive on networks with many accounts
//! - May cause performance degradation or OOM conditions on large state
//!
//! If you find yourself wanting to use this method outside of the stress test
//! framework, you are likely doing something wrong. Please reconsider your approach.

use rialo_shared_types::AccountInfoResponseValue;
use serde::{Deserialize, Serialize};

use super::rpc_response_context::RpcResponseContext;

/// Request parameters for the `getAllAccounts` RPC method.
///
/// This method takes no parameters and returns all accounts in the system.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct GetAllAccountsRequest {
    /// Optional configuration for the request.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub config: Option<GetAllAccountsConfig>,
}

impl GetAllAccountsRequest {
    pub fn new() -> Self {
        Self::default()
    }
}

/// Configuration for getAllAccounts request.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct GetAllAccountsConfig {
    /// Data encoding format (currently only base64 is supported).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub encoding: Option<String>,
    /// Whether to include account data in the response.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub include_data: Option<bool>,
}

/// A single account returned by getAllAccounts.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AllAccountsEntry {
    /// The account's public key (base58-encoded).
    pub pubkey: String,
    /// The account information.
    pub account: AccountInfoResponseValue,
}

/// Response from the `getAllAccounts` RPC method.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GetAllAccountsResponse {
    /// Response context with slot information.
    pub context: RpcResponseContext,
    /// Array of all accounts.
    pub value: Vec<AllAccountsEntry>,
}

impl GetAllAccountsResponse {
    pub fn new(slot: u64, accounts: Vec<AllAccountsEntry>) -> Self {
        Self {
            context: RpcResponseContext::new(slot),
            value: accounts,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_get_all_accounts_request_default() {
        let request = GetAllAccountsRequest::new();
        assert!(request.config.is_none());
    }

    #[test]
    fn test_get_all_accounts_request_serialization() {
        let request = GetAllAccountsRequest::new();
        let json = serde_json::to_string(&request).unwrap();
        assert_eq!(json, "{}");
    }

    #[test]
    fn test_get_all_accounts_response_serialization() {
        let response = GetAllAccountsResponse::new(100, vec![]);
        let json = serde_json::to_string(&response).unwrap();
        assert!(json.contains("\"context\""));
        assert!(json.contains("\"value\":[]"));
    }
}
