use super::*;

impl AppCore {
    pub(super) fn build_runtime_debug_snapshot(&self) -> RuntimeDebugSnapshot {
        let current_protocol_plan =
            self.compute_protocol_subscription_plan()
                .map(|plan| RuntimeProtocolPlanDebug {
                    runtime_subscriptions: plan.runtime_subscriptions,
                });
        let tracked_owner_hexes = sorted_hexes(self.tracked_peer_owner_hexes());
        let current_chat_list = self.threads.keys().cloned().collect::<Vec<_>>();
        let (local_owner_pubkey_hex, local_device_pubkey_hex, authorization_state) =
            if let Some(logged_in) = self.logged_in.as_ref() {
                (
                    Some(logged_in.owner_pubkey.to_hex()),
                    Some(local_device_from_keys(&logged_in.device_keys).to_hex()),
                    Some(format!("{:?}", logged_in.authorization_state)),
                )
            } else {
                (None, None, None)
            };
        let known_users = self
            .app_keys
            .values()
            .map(|known| RuntimeKnownUserDebug {
                owner_pubkey_hex: known.owner_pubkey_hex.clone(),
                has_roster: true,
                roster_device_count: known.devices.len(),
                device_count: known.devices.len(),
                authorized_device_count: known.devices.len(),
                active_session_device_count: 0,
                inactive_session_count: 0,
            })
            .collect::<Vec<_>>();

        RuntimeDebugSnapshot {
            generated_at_secs: unix_now().get(),
            local_owner_pubkey_hex,
            local_device_pubkey_hex,
            authorization_state,
            active_chat_id: self.active_chat_id.clone(),
            current_protocol_plan,
            tracked_owner_hexes,
            known_users,
            recent_handshake_peers: self
                .recent_handshake_peers
                .values()
                .map(|peer| RuntimeRecentHandshakeDebug {
                    owner_hex: peer.owner_hex.clone(),
                    device_hex: peer.device_hex.clone(),
                    observed_at_secs: peer.observed_at_secs,
                })
                .collect(),
            event_counts: self.debug_event_counters.clone(),
            recent_log: self.debug_log.iter().cloned().collect(),
            toast: self.state.toast.clone(),
            current_chat_list,
        }
    }

    pub(super) fn export_support_bundle_json(&self) -> String {
        serde_json::to_string_pretty(&self.build_support_bundle())
            .unwrap_or_else(|_| "{}".to_string())
    }

    pub(super) fn build_support_bundle(&self) -> SupportBundle {
        let runtime = self.build_runtime_debug_snapshot();
        let current_screen = self
            .screen_stack
            .last()
            .cloned()
            .unwrap_or_else(|| self.state.router.default_screen.clone());
        let direct_chat_count = self
            .threads
            .keys()
            .filter(|chat_id| !is_group_chat_id(chat_id))
            .count();
        let group_chat_count = self
            .threads
            .keys()
            .filter(|chat_id| is_group_chat_id(chat_id))
            .count();
        let unread_chat_count = self
            .threads
            .values()
            .filter(|thread| thread.unread_count > 0)
            .count();

        SupportBundle {
            generated_at_secs: unix_now().get(),
            build: SupportBuildMetadata {
                app_version: APP_VERSION.to_string(),
                build_channel: BUILD_CHANNEL.to_string(),
                git_sha: BUILD_GIT_SHA.to_string(),
                build_timestamp_utc: BUILD_TIMESTAMP_UTC.to_string(),
                relay_set_id: RELAY_SET_ID.to_string(),
                trusted_test_build: trusted_test_build(),
            },
            relay_urls: self.preferences.nostr_relay_urls.clone(),
            authorization_state: runtime.authorization_state,
            active_chat_id: runtime.active_chat_id,
            current_screen: format!("{current_screen:?}"),
            chat_count: self.threads.len(),
            direct_chat_count,
            group_chat_count,
            unread_chat_count,
            protocol: runtime.current_protocol_plan,
            tracked_owner_hexes: runtime.tracked_owner_hexes,
            known_users: runtime.known_users,
            recent_handshake_peers: runtime.recent_handshake_peers,
            event_counts: runtime.event_counts,
            recent_log: runtime.recent_log,
            current_chat_list: runtime.current_chat_list,
            latest_toast: runtime.toast,
        }
    }

    pub(super) fn push_debug_log(&mut self, category: &str, detail: impl Into<String>) {
        self.debug_log.push_back(DebugLogEntry {
            timestamp_secs: unix_now().get(),
            category: category.to_string(),
            detail: detail.into(),
        });
        while self.debug_log.len() > MAX_DEBUG_LOG_ENTRIES {
            self.debug_log.pop_front();
        }
    }

    pub(crate) fn mark_core_panic(&mut self, detail: String) {
        crate::perflog!("core.batch.panic detail={detail}");
        self.push_debug_log("core.panic", detail);
        self.state.toast = Some("Iris needs restart. Copy support bundle in Settings.".to_string());
        self.persist_debug_snapshot_best_effort();
        self.emit_state();
    }
}
