// Copyright 2023 PingCAP, Inc.

use std::sync::atomic::{AtomicUsize, Ordering};

use native_br::{
    packing::ReportPackBackupStepTrait,
    restore_keyspace::{ReportRestoreStepTrait, RestoreStep},
};
use rand::Rng;
use test_cloud_server::{ServerCluster, must_wait};

mod archive;
mod backup;
mod limiter;
mod restore_keyspace;

fn random_value<const N: usize>(_: usize) -> Vec<u8>
where
    [u8; N]: rand::Fill,
{
    let mut bytes = [0u8; N];
    rand::thread_rng().fill(&mut bytes);
    bytes.to_vec()
}

fn i_to_key(i: usize) -> Vec<u8> {
    format!("tkey_{:08}", i).into_bytes()
}

fn random_val() -> Vec<u8> {
    let mut bytes = [0u8; 64];
    rand::thread_rng().fill(&mut bytes);
    bytes.to_vec()
}

fn i_to_val(expected_len: usize) -> impl Fn(usize) -> Vec<u8> {
    const RANDOM_VALUE_LEN: usize = 64;

    assert!(
        expected_len > 8 + RANDOM_VALUE_LEN,
        "expected_len: {} is not larger than 72",
        expected_len
    );
    move |i: usize| -> Vec<u8> {
        let mut val = format!("{:08}", i).into_bytes();
        let mut padding = vec![b'0'; expected_len - 8 - RANDOM_VALUE_LEN];
        val.append(&mut padding);
        val.append(&mut random_val());
        val
    }
}

fn gen_keyspace_key(keyspace_id: u32) -> impl Fn(usize) -> Vec<u8> {
    move |i: usize| -> Vec<u8> {
        let mut key = api_version::ApiV2::get_keyspace_prefix_by_id(keyspace_id);
        key.extend(i_to_key(i));
        key
    }
}

fn generate_backup_name() -> String {
    static BACKUP_ID: AtomicUsize = AtomicUsize::new(0);
    format!("{:04}", BACKUP_ID.fetch_add(1, Ordering::Relaxed))
}

fn wait_all_dfs_workers_healthy(cluster: &ServerCluster, msg: &str) {
    must_wait(
        || {
            cluster
                .get_nodes()
                .into_iter()
                .all(|node_id| cluster.get_rfengine(node_id).is_dfs_worker_healthy())
        },
        30,
        || msg.to_string(),
    );
}

#[derive(Default)]
struct DummyStepReporter {}

impl ReportRestoreStepTrait for DummyStepReporter {
    fn report_step(&self, _step: RestoreStep) {}
}

impl ReportPackBackupStepTrait for DummyStepReporter {
    fn report_step(&self, _step: native_br::packing::PackBackupStep) {}
}
