use super::storage::SaveSnapshot;
use super::*;

// Durable app state lives in `data_dir/core.sqlite3` (managed by
// `core::storage`). The notification-extension preview cache and the
// runtime debug snapshot are still file-backed because they must be
// readable from contexts that don't open the SQLite database (the
// FCM service / iOS Notification Service Extension paths read JSON
// directly).

impl AppCore {
    pub(super) fn debug_snapshot_path(&self) -> PathBuf {
        self.data_dir.join(DEBUG_SNAPSHOT_FILENAME)
    }

    pub(super) fn load_persisted(&mut self) -> anyhow::Result<Option<PersistedState>> {
        self.app_store.delete_expired_messages(unix_now().get())?;
        self.app_store.load_state()
    }

    pub(super) fn persist_best_effort(&mut self) {
        if self.batch_depth > 0 {
            self.batch_dirty_persist = true;
            return;
        }
        self.persist_best_effort_inner();
    }

    pub(super) fn persist_best_effort_inner(&mut self) {
        if self.logged_in.is_none() {
            return;
        }

        let authorization_state = self
            .logged_in
            .as_ref()
            .map(|logged_in| logged_in.authorization_state.into());
        let snapshot = SaveSnapshot {
            active_chat_id: self.active_chat_id.as_deref(),
            next_message_id: self.next_message_id,
            authorization_state,
            preferences: &self.preferences,
            owner_profiles: &self.owner_profiles,
            chat_message_ttl_seconds: &self.chat_message_ttl_seconds,
            app_keys: &self.app_keys,
            groups: &self.groups,
            threads: &self.threads,
            seen_event_order: &self.seen_event_order,
        };
        if let Err(error) = self.app_store.save_state(&snapshot) {
            self.push_debug_log("storage.save_failed", error.to_string());
        }

        self.persist_debug_snapshot_best_effort();
    }

    pub(super) fn clear_persistence_best_effort(&mut self) {
        if let Err(error) = self.app_store.clear() {
            self.push_debug_log("storage.clear_failed", error.to_string());
        }
        let debug_path = self.debug_snapshot_path();
        if debug_path.exists() {
            let _ = fs::remove_file(debug_path);
        }
    }

    pub(super) fn persist_debug_snapshot_best_effort(&self) {
        if self.logged_in.is_none() {
            return;
        }
        let snapshot = self.build_runtime_debug_snapshot();
        let path = self.debug_snapshot_path();
        let data_dir = self.data_dir.clone();
        self.runtime.spawn_blocking(move || {
            if let Ok(bytes) = serde_json::to_vec_pretty(&snapshot) {
                let _ = fs::create_dir_all(&data_dir);
                let _ = fs::write(path, bytes);
            }
        });
    }
}
