//! Central registry of admin resources indexed by URL key.
use indexmap::IndexMap;

use crate::admin::helper::resource_entry::ResourceEntry;
use crate::admin::resource::DisplayConfig;

/// Admin resource registry — IndexMap key → ResourceEntry.
///
/// Powered by the code generated by the daemon (`src/admins/generated.rs`).
/// Shared read-only via `Arc<AdminRegistry>` in the Axum state.
/// Insertion order (order in `generated.rs`) is preserved.
#[derive(Default)]
pub struct AdminRegistry {
    pub resources: IndexMap<String, ResourceEntry>,
}

impl AdminRegistry {
    pub fn new() -> Self {
        Self {
            resources: IndexMap::new(),
        }
    }

    /// Registers a resource. Called by generated code at boot.
    pub fn register(&mut self, entry: ResourceEntry) {
        self.resources.insert(entry.meta.key.to_string(), entry);
    }

    /// Lookup by URL key (e.g., "users", "blog")
    pub fn get(&self, key: &str) -> Option<&ResourceEntry> {
        self.resources.get(key)
    }

    pub fn all(&self) -> impl Iterator<Item = &ResourceEntry> {
        self.resources.values()
    }

    pub fn is_empty(&self) -> bool {
        self.resources.is_empty()
    }

    pub fn len(&self) -> usize {
        self.resources.len()
    }

    pub fn contains(&self, key: &str) -> bool {
        self.resources.contains_key(key)
    }

    pub fn keys(&self) -> Vec<&str> {
        self.resources.keys().map(|k| k.as_str()).collect()
    }

    /// Applies a display configuration to an existing resource (built-in or declared).
    ///
    /// Called by generated code after `admin_register()` for entries in the `configure {}` block.
    /// No effect if the key does not exist.
    pub fn configure(&mut self, key: &str, display: DisplayConfig) {
        if let Some(entry) = self.resources.get_mut(key) {
            entry.meta.display = display;
        }
    }

    /// Applies group actions to an existing resource (built-in or declared).
    pub fn configure_group_actions(
        &mut self,
        key: &str,
        actions: Vec<crate::admin::helper::resource_entry::GroupAction>,
    ) {
        if let Some(entry) = self.resources.get_mut(key) {
            entry.group_actions = actions;
        }
    }

    /// Removes a resource from the registry (e.g., to hide a builtin when extend!{} takes over).
    pub fn remove(&mut self, key: &str) {
        self.resources.shift_remove(key);
    }

    /// Reorders the registry according to the provided list of keys.
    /// Unlisted keys are added at the end in their insertion order.
    pub fn reorder(&mut self, order: &[String]) {
        let mut reordered = indexmap::IndexMap::new();
        for key in order {
            if let Some(entry) = self.resources.shift_remove(key.as_str()) {
                reordered.insert(key.clone(), entry);
            }
        }
        // Remaining unlisted keys
        for (key, entry) in std::mem::take(&mut self.resources) {
            reordered.insert(key, entry);
        }
        self.resources = reordered;
    }
}
