// Copyright 2026 PingCAP, Inc.

use std::sync::Arc;

use file_system::IoRateLimiter;
use tikv::{
    config::*,
    storage::{
        TestEngineBuilder, TestStorageBuilderApiV1, config_manager::StorageConfigManager,
        lock_manager::MockLockManager,
    },
};
use tikv_util::config::ReadableDuration;

#[test]
fn test_storage_online_config() {
    let (mut cfg, _dir) = TikvConfig::with_tmp().unwrap();
    cfg.storage.max_txn_file_locks_per_region = 1;
    cfg.validate().unwrap();
    let use_separated_scheduler_pool = cfg.storage.use_separated_scheduler_pool;

    let storage = TestStorageBuilderApiV1::from_engine_and_lock_mgr(
        TestEngineBuilder::new().build().unwrap(),
        MockLockManager::new(),
    )
    .config(cfg.storage.clone())
    .build()
    .unwrap();
    let scheduler = storage.get_scheduler();
    let runtime_config = storage.get_runtime_config();
    let read_reschedule_config = storage.get_read_reschedule_config();
    assert!(!runtime_config.enable_get_in_read_pool());
    let options = read_reschedule_config.snapshot();
    assert_eq!(options.range_scan_reschedule_check_keys, 32);
    assert_eq!(options.range_scan_max_time_slice_us, 3000);
    assert_eq!(options.batch_get_fairness_checkpoint_keys, 32);
    assert_eq!(options.cloud_store_fair_cpu_checkpoint_entries, 512);
    assert_eq!(scheduler.get_max_txn_file_locks_per_region(), 1);
    assert_eq!(
        scheduler.get_async_resolve_lock_batch_interval(),
        ReadableDuration::millis(500).0
    );

    let cfg_controller = ConfigController::new(cfg);
    cfg_controller.register(
        Module::Storage,
        Box::new(StorageConfigManager::new(
            storage.get_engine(),
            storage.get_concurrency_manager(),
            Arc::new(IoRateLimiter::new_for_test()),
            scheduler.clone(),
            runtime_config.clone(),
            use_separated_scheduler_pool,
        )),
    );

    cfg_controller
        .update_config("storage.enable-get-in-read-pool", "true")
        .unwrap();
    assert!(cfg_controller.get_current().storage.enable_get_in_read_pool);
    assert!(runtime_config.enable_get_in_read_pool());

    cfg_controller
        .update_config("storage.enable-get-in-read-pool", "false")
        .unwrap();
    assert!(!cfg_controller.get_current().storage.enable_get_in_read_pool);
    assert!(!runtime_config.enable_get_in_read_pool());

    cfg_controller
        .update_config("storage.max-txn-file-locks-per-region", "2")
        .unwrap();
    assert_eq!(scheduler.get_max_txn_file_locks_per_region(), 2);
    assert_eq!(
        cfg_controller
            .get_current()
            .storage
            .max_txn_file_locks_per_region,
        2
    );

    cfg_controller
        .update_config("storage.max-txn-file-locks-per-region", "0")
        .unwrap();
    assert_eq!(scheduler.get_max_txn_file_locks_per_region(), 0);
    assert_eq!(
        cfg_controller
            .get_current()
            .storage
            .max_txn_file_locks_per_region,
        0
    );

    cfg_controller
        .update_config("storage.scheduler-async-resolve-lock-batch-interval", "0s")
        .unwrap();
    assert_eq!(
        scheduler.get_async_resolve_lock_batch_interval(),
        ReadableDuration::ZERO.0
    );
    assert_eq!(
        cfg_controller
            .get_current()
            .storage
            .scheduler_async_resolve_lock_batch_interval,
        ReadableDuration::ZERO
    );

    cfg_controller
        .update_config("storage.range-scan-reschedule-check-keys", "64")
        .unwrap();
    cfg_controller
        .update_config("storage.range-scan-max-time-slice-us", "1000")
        .unwrap();
    cfg_controller
        .update_config("storage.batch-get-fairness-checkpoint-keys", "96")
        .unwrap();
    cfg_controller
        .update_config("storage.cloud-store-fair-cpu-checkpoint-entries", "1024")
        .unwrap();
    let options = read_reschedule_config.snapshot();
    assert_eq!(options.range_scan_reschedule_check_keys, 64);
    assert_eq!(options.range_scan_max_time_slice_us, 1000);
    assert_eq!(options.batch_get_fairness_checkpoint_keys, 96);
    assert_eq!(options.cloud_store_fair_cpu_checkpoint_entries, 1024);
    assert_eq!(
        options.range_scan().max_time_slice,
        std::time::Duration::from_micros(1000)
    );

    // Out-of-range updates are rejected and leave the running value alone.
    cfg_controller
        .update_config("storage.range-scan-max-time-slice-us", "0")
        .unwrap_err();
    assert_eq!(
        read_reschedule_config
            .snapshot()
            .range_scan_max_time_slice_us,
        1000
    );
}
