use std::{collections::HashMap, sync::Arc};

use anyhow::Result;
use tici::{
    config::{make_default_test_meta_config, make_default_test_worker_config},
    meta::writer::{GcTask, ShardStatsCollectorTask},
};
use tici_system::readable::ReadableDuration;
use tici_test_utils::test_utils::test_suite::E2ETestSuite;

fn change(name: &str, value: &str) -> HashMap<String, String> {
    let mut m = HashMap::new();
    m.insert(name.to_owned(), value.to_owned());
    m
}

#[test]
fn test_config_update() -> Result<()> {
    let rt: tokio::runtime::Runtime = tokio::runtime::Builder::new_multi_thread()
        .worker_threads(4)
        .enable_all()
        .build()?;

    rt.block_on(async {
        let test_suite = E2ETestSuite::new_with_mock_cfg(
            make_default_test_meta_config(false),
            make_default_test_worker_config(false),
        )
        .await
        .unwrap();

        let mut cfg = test_suite
            .get_meta_service()
            .config
            .load_full()
            .as_ref()
            .clone();
        cfg.shard.gc_config.gc_worker_check_interval = ReadableDuration::millis(12344321);
        test_suite
            .get_meta_service()
            .shard_task_manager
            .config
            .store(Arc::new(cfg.clone()));

        let new_meta = test_suite.get_meta_service();
        assert_eq!(new_meta.shard_task_manager.config.load().as_ref(), &cfg);
        assert_eq!(new_meta.worker_node_mgr.cloned_config().as_ref(), &cfg);
        let (tx, rx) = tokio::sync::oneshot::channel();
        new_meta
            .shard_task_manager
            .get_gc_worker()
            .get_tx()
            .send(GcTask::GetConfig(tx))
            .unwrap();
        assert_eq!(rx.await.unwrap().as_ref(), &cfg);
        let (tx, rx) = tokio::sync::oneshot::channel();
        new_meta
            .shard_task_manager
            .get_shard_patrol()
            .get_tx()
            .send(ShardStatsCollectorTask::GetConfig(tx))
            .unwrap();
        assert_eq!(rx.await.unwrap().as_ref(), &cfg);
    });

    Ok(())
}

#[test]
fn test_config_change() -> Result<()> {
    let rt: tokio::runtime::Runtime = tokio::runtime::Builder::new_multi_thread()
        .worker_threads(4)
        .enable_all()
        .build()?;

    rt.block_on(async {
        let test_suite = E2ETestSuite::new_with_mock_cfg(
            make_default_test_meta_config(false),
            make_default_test_worker_config(false),
        )
        .await
        .unwrap();

        let meta = test_suite.get_meta_handle();

        let c = change("shard.gc_config.gc_worker_check_interval", "1234567ms");
        meta.meta_service.update_config(c).unwrap();
        assert_eq!(
            meta.meta_service
                .shard_task_manager
                .config
                .load()
                .shard
                .gc_config
                .gc_worker_check_interval,
            ReadableDuration::millis(1234567)
        );

        let c = change("server.addr", "hahaha");
        meta.meta_service.update_config(c).unwrap_err();
    });

    Ok(())
}
