// This code is automatically generated by Senax and is always overwritten.

use ::std::sync::Arc;
use ::anyhow::Result;
use ::async_trait::async_trait;
use db::DbConn;
use ::futures::future::BoxFuture;
use ::fxhash::FxHashMap;
use ::senax_common::{cache::msec::MSec, ShardId};
@% for (name, defs) in groups %@
pub mod @{ name|snake|ident }@;
@%- endfor %@

pub struct CacheHandler;
#[async_trait]
impl db::models::CacheHandler for CacheHandler {
    #[allow(unreachable_patterns)]
    async fn handle_cache_msg(&self, op: Vec<db::CacheOp>, sync_map: Arc<FxHashMap<ShardId, u64>>) {
        use db::CacheOp;
        for op in op.into_iter() {
            match op {
                @%- for (name, defs) in groups %@
                CacheOp::@{ name|pascal|ident }@(op) => op.handle_cache_msg(Arc::clone(&sync_map)).await,
                @%- endfor %@
                CacheOp::_AllClear => _clear_cache(&sync_map, false).await,
                _ => {},
            };
        }
    }
    async fn clear_cache(&self, shard_id: ShardId, sync: u64, clear_test: bool) {
        @%- for (name, defs) in groups %@
        @{ name|snake|ident }@::_clear_cache(shard_id, sync, clear_test).await;
        @%- endfor %@
    }
}

pub(crate) async fn _clear_cache(_sync_map: &FxHashMap<ShardId, u64>, clear_test: bool) {
    for (shard_id, sync) in _sync_map.iter() {
        if *sync == 0 && !clear_test {
            let shard_id = *shard_id;
            tokio::spawn(async move {
                tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
                @%- for (name, defs) in groups %@
                @{ name|snake|ident }@::_clear_cache(shard_id, 0, clear_test).await;
                @%- endfor %@
            });
        }
        @%- for (name, defs) in groups %@
        @{ name|snake|ident }@::_clear_cache(*shard_id, *sync, clear_test).await;
        @%- endfor %@
    }
}

trait GroupCacheOpTr {
    async fn handle_cache_msg(self, sync_map: Arc<FxHashMap<ShardId, u64>>);
}

#[allow(dead_code)]
#[allow(unused_variables)]
pub trait CacheOpTr<CacheOp, OpData, Data, CacheWrapper, CacheData, PrimaryHasher> {
    fn apply_to_obj(obj: &Option<Arc<CacheWrapper>>, msgs: &[CacheOp], shard_id: ShardId, time: MSec) -> Option<Arc<CacheWrapper>> {
        unimplemented!("apply_to_obj is disabled.")
    }
    fn apply_to_list(_list: &[Arc<CacheWrapper>], msgs: &[CacheOp], shard_id: ShardId, time: MSec) -> Vec<Arc<CacheWrapper>> {
        unimplemented!("apply_to_list is disabled.")
    }
    fn update_with_unique_cache(id: &PrimaryHasher, obj: CacheData, update: &Data, op: &OpData, time: MSec) -> impl std::future::Future<Output = CacheData> + Send {
        async {
            unimplemented!("update_with_unique_cache is disabled.")
        }
    }
    fn handle_cache_msg(self, sync_map: Arc<FxHashMap<ShardId, u64>>) -> BoxFuture<'static, ()>;
}

#[rustfmt::skip]
#[allow(clippy::single_match)]
#[allow(clippy::match_single_binding)]
pub async fn seed(seed: &serde_yaml::Value, conns: &mut [DbConn]) -> Result<()> {
    if let Some(mapping) = seed.as_mapping() {
        for (name, value) in mapping {
            match name.as_str() {
@% for (name, defs) in groups %@
                Some("@{ name }@") => @{ name|snake|ident }@::seed(value, conns).await?,
@%- endfor %@
                _ => {}
            }
        }
    }
    Ok(())
}
@{-"\n"}@