//! Test helper impls.

#![allow(dead_code)]

#[cfg(any(test, feature = "file-client"))]
use crate::{bodies::test_utils::create_raw_bodies, file_codec::BlockFileCodec};
use alloy_primitives::{map::B256Map, B256};
use reth_ethereum_primitives::BlockBody;
use reth_testing_utils::generators::{self, random_block_range, BlockRangeParams};
use std::ops::RangeInclusive;

mod bodies_client;
pub use bodies_client::TestBodiesClient;
use reth_primitives_traits::SealedHeader;

/// Metrics scope used for testing.
pub(crate) const TEST_SCOPE: &str = "downloaders.test";

/// Generate a set of bodies and their corresponding block hashes
pub(crate) fn generate_bodies(
    range: RangeInclusive<u64>,
) -> (Vec<SealedHeader>, B256Map<BlockBody>) {
    let mut rng = generators::rng();
    let blocks = random_block_range(
        &mut rng,
        range,
        BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..2, ..Default::default() },
    );

    let headers = blocks.iter().map(|block| block.clone_sealed_header()).collect();
    let bodies = blocks.into_iter().map(|block| (block.hash(), block.into_body())).collect();

    (headers, bodies)
}

/// Generate a set of bodies, write them to a temporary file, and return the file along with the
/// bodies and corresponding block hashes
#[cfg(any(test, feature = "file-client"))]
pub(crate) async fn generate_bodies_file(
    range: RangeInclusive<u64>,
) -> (tokio::fs::File, Vec<SealedHeader>, B256Map<BlockBody>) {
    use futures::SinkExt;
    use std::io::SeekFrom;
    use tokio::{fs::File, io::AsyncSeekExt};
    use tokio_util::codec::FramedWrite;

    let (headers, bodies) = generate_bodies(range);
    let raw_block_bodies = create_raw_bodies(headers.iter().cloned(), &mut bodies.clone());

    let file: File = tempfile::tempfile().unwrap().into();
    let mut writer = FramedWrite::new(file, BlockFileCodec::default());

    // rlp encode one after the other
    for block in raw_block_bodies {
        writer.feed(block).await.unwrap();
    }
    writer.flush().await.unwrap();

    // get the file back
    let mut file: File = writer.into_inner();
    file.seek(SeekFrom::Start(0)).await.unwrap();
    (file, headers, bodies)
}
