use magnetar_common::config::MagnetarConfig;
use magnetar_model::{ck, CalckeyCache, CalckeyModel};
use std::fmt::{Debug, Formatter};
use std::time::Duration;
use thiserror::Error;

pub mod emoji_cache;
pub mod generic_id_cache;
pub mod instance_cache;
pub mod instance_meta_cache;
pub mod local_user_cache;

#[non_exhaustive]

pub struct MagnetarService {
    pub db: CalckeyModel,
    pub cache: CalckeyCache,
    pub config: &'static MagnetarConfig,
    pub local_user_cache: local_user_cache::LocalUserCacheService,
    pub instance_meta_cache: instance_meta_cache::InstanceMetaCacheService,
    pub remote_instance_cache: instance_cache::RemoteInstanceCacheService,
    pub emoji_cache: emoji_cache::EmojiCacheService,
    pub drive_file_cache: generic_id_cache::GenericIdCacheService<ck::drive_file::Entity>,
}

impl Debug for MagnetarService {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("MagnetarService")
            .field("db", &self.db)
            .field("cache", &self.cache)
            .field("config", &self.config)
            .finish_non_exhaustive()
    }
}

#[derive(Debug, Error)]
pub enum ServiceInitError {
    #[error("Authentication cache initialization error: {0}")]
    AuthCacheError(#[from] local_user_cache::UserCacheError),
}

impl MagnetarService {
    pub async fn new(
        config: &'static MagnetarConfig,
        db: CalckeyModel,
        cache: CalckeyCache,
    ) -> Result<Self, ServiceInitError> {
        let local_user_cache =
            local_user_cache::LocalUserCacheService::new(config, db.clone(), cache.clone()).await?;
        let instance_meta_cache = instance_meta_cache::InstanceMetaCacheService::new(db.clone());
        let emoji_cache = emoji_cache::EmojiCacheService::new(db.clone());
        let remote_instance_cache = instance_cache::RemoteInstanceCacheService::new(
            db.clone(),
            config,
            256,
            Duration::from_secs(100),
        );
        let drive_file_cache =
            generic_id_cache::GenericIdCacheService::new(db.clone(), 128, Duration::from_secs(10));

        Ok(Self {
            db,
            cache,
            config,
            local_user_cache,
            instance_meta_cache,
            remote_instance_cache,
            emoji_cache,
            drive_file_cache,
        })
    }
}
