use lazy_static::lazy_static;
use tici_common::{cdc_file_name::CDCFileName, index::IndexKey};
use tici_grpc::{FragStorageRef, ShardManifestHeader};
use uuid::Uuid;

use super::{TEST_S3_BUCKET, TEST_S3_PREFIX, index_meta::TEST_INDEX_KEY};
use crate::{
    FragLocation, ShardMirrorMeta, ShardMirrorMetaVersion, ShardWriterMeta, ShardWriterMetaVersion,
};

lazy_static! {
    pub static ref TEST_INF_START: [u8;0] = [];
    // Use a large enough end to represent infinity, just for testing
    pub static ref TEST_INF_END: [u8;1024] = [255; 1024];
    // The table_id in test data ci/cdc_test_data.zip was 123
    pub static ref TEST_TABLE_PREFIX: String = format!("{}/123", TEST_S3_PREFIX.clone());
    // Use one partition table_id (437) for test data in ci/cdc_test_partition_data.zip.
    pub static ref TEST_PARTITION_TABLE_PREFIX: String = format!("{}/437", TEST_S3_PREFIX.clone());

    pub static ref TEST_SHARD_META: ShardWriterMeta = ShardWriterMeta {
        version: ShardWriterMetaVersion::LATEST,
        index_key: TEST_INDEX_KEY.clone(),
        shard_header: ShardManifestHeader {
            start_key: TEST_INF_START.to_vec(),
            end_key: TEST_INF_END.to_vec(),
            shard_id: 3,
            epoch: 4,
            seq: 5,
        },
        frag_location: FragLocation {
            bucket: TEST_S3_BUCKET.to_string(),
            prefix: String::new(),
        },
        cdc_checkpoint: crate::CDCCheckpoint {
            bucket: TEST_S3_BUCKET.to_string(),
            table_prefix: TEST_TABLE_PREFIX.to_string(),
            last_file: CDCFileName::empty(),
        },
    };

    pub static ref TEST_FRAG_STORAGE_REFS: Vec<FragStorageRef> = vec![FragStorageRef {
        sub_key: "mock_frag_storage_ref".to_string(),
        offset: 0,
        size: 1,
    }];
}

pub fn test_mock_frag_storage_refs() -> Vec<FragStorageRef> {
    TEST_FRAG_STORAGE_REFS.clone()
}

/// Storage refs whose sizes sum to `total` (single object). Use when
/// [`tici_grpc::FragProperty::size`] must match that sum.
pub fn test_mock_frag_storage_refs_total(total: u64) -> Vec<FragStorageRef> {
    assert!(
        total > 0,
        "test_mock_frag_storage_refs_total: total must be > 0"
    );
    vec![FragStorageRef {
        sub_key: "mock_frag_storage_ref".to_string(),
        offset: 0,
        size: total,
    }]
}

pub fn test_get_shard_writer_meta() -> ShardWriterMeta {
    let mut shard_meta = TEST_SHARD_META.clone();
    shard_meta.frag_location.prefix = Uuid::new_v4().to_string();
    shard_meta
}

pub fn test_get_shard_mirror_meta(shard_writer_meta: &ShardWriterMeta) -> ShardMirrorMeta {
    ShardMirrorMeta {
        version: ShardMirrorMetaVersion::LATEST,
        index_key: shard_writer_meta.index_key.clone(),
        shard_header: shard_writer_meta.shard_header.clone(),
        frag_bucket: shard_writer_meta.frag_location.bucket.clone(),
    }
}

pub fn mock_custom_shard_meta(
    index_key: IndexKey,
    shard_id: u64,
    start: Vec<u8>,
    end: Vec<u8>,
    frag_prefix: String,
) -> ShardWriterMeta {
    let mut shard_meta = TEST_SHARD_META.clone();
    shard_meta.index_key = index_key;
    shard_meta.shard_header.shard_id = shard_id;
    shard_meta.shard_header.start_key = start;
    shard_meta.shard_header.end_key = end;
    shard_meta.frag_location.prefix = frag_prefix;
    shard_meta
}
