//! Auto-generated from @klodi/tool-catalog. DO NOT EDIT.
//!
//! Source: klodi-plugin/packages/tool-catalog/src/index.ts
//! Regenerate with: pnpm --filter @klodi/tool-catalog codegen

use serde::{Deserialize, Serialize};

// ─── Cross-language constants (D9, D14) ──────────────────────────────
/// KLODI_DEFAULT_API_URL — see klodi-plugin/packages/tool-catalog/src/index.ts.
pub const KLODI_DEFAULT_API_URL: &str = "https://klodi.4gpts.com";
/// KLODI_DEFAULT_NATS_URL — see klodi-plugin/packages/tool-catalog/src/index.ts.
pub const KLODI_DEFAULT_NATS_URL: &str = "wss://klodi-net.4gpts.com";
/// MAX_CHANNEL_MESSAGE_CHARS — see klodi-plugin/packages/tool-catalog/src/index.ts.
pub const MAX_CHANNEL_MESSAGE_CHARS: usize = 2000;
/// REGISTER_POLL_INTERVAL_SECONDS — see klodi-plugin/packages/tool-catalog/src/index.ts.
pub const REGISTER_POLL_INTERVAL_SECONDS: usize = 5;
/// REGISTER_POLL_CEILING_SECONDS — see klodi-plugin/packages/tool-catalog/src/index.ts.
pub const REGISTER_POLL_CEILING_SECONDS: usize = 600;

/// Every klodi_* tool name as a strongly-typed enum.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum ToolName {
    /// klodi_whoami
    KlodiWhoami,
    /// klodi_ratings
    KlodiRatings,
    /// klodi_list_create
    KlodiListCreate,
    /// klodi_list_update
    KlodiListUpdate,
    /// klodi_list_get
    KlodiListGet,
    /// klodi_list_mine
    KlodiListMine,
    /// klodi_list_withdraw
    KlodiListWithdraw,
    /// klodi_list_relist
    KlodiListRelist,
    /// klodi_list_comments
    KlodiListComments,
    /// klodi_search
    KlodiSearch,
    /// klodi_searches_create
    KlodiSearchesCreate,
    /// klodi_searches_delete
    KlodiSearchesDelete,
    /// klodi_searches_list
    KlodiSearchesList,
    /// klodi_channel_create
    KlodiChannelCreate,
    /// klodi_channel_mine
    KlodiChannelMine,
    /// klodi_channel_history
    KlodiChannelHistory,
    /// klodi_channel_close
    KlodiChannelClose,
    /// klodi_comment
    KlodiComment,
    /// klodi_offer_create
    KlodiOfferCreate,
    /// klodi_offer_respond
    KlodiOfferRespond,
    /// klodi_offer_mine
    KlodiOfferMine,
    /// klodi_tx_confirm
    KlodiTxConfirm,
    /// klodi_tx_cancel
    KlodiTxCancel,
    /// klodi_tx_rate
    KlodiTxRate,
    /// klodi_tx_status
    KlodiTxStatus,
    /// klodi_assets_upload_url
    KlodiAssetsUploadUrl,
}

impl ToolName {
    /// The public tool name as agents call it (e.g. "klodi_list_create").
    pub fn name(&self) -> &'static str {
        match self {
            ToolName::KlodiWhoami => "klodi_whoami",
            ToolName::KlodiRatings => "klodi_ratings",
            ToolName::KlodiListCreate => "klodi_list_create",
            ToolName::KlodiListUpdate => "klodi_list_update",
            ToolName::KlodiListGet => "klodi_list_get",
            ToolName::KlodiListMine => "klodi_list_mine",
            ToolName::KlodiListWithdraw => "klodi_list_withdraw",
            ToolName::KlodiListRelist => "klodi_list_relist",
            ToolName::KlodiListComments => "klodi_list_comments",
            ToolName::KlodiSearch => "klodi_search",
            ToolName::KlodiSearchesCreate => "klodi_searches_create",
            ToolName::KlodiSearchesDelete => "klodi_searches_delete",
            ToolName::KlodiSearchesList => "klodi_searches_list",
            ToolName::KlodiChannelCreate => "klodi_channel_create",
            ToolName::KlodiChannelMine => "klodi_channel_mine",
            ToolName::KlodiChannelHistory => "klodi_channel_history",
            ToolName::KlodiChannelClose => "klodi_channel_close",
            ToolName::KlodiComment => "klodi_comment",
            ToolName::KlodiOfferCreate => "klodi_offer_create",
            ToolName::KlodiOfferRespond => "klodi_offer_respond",
            ToolName::KlodiOfferMine => "klodi_offer_mine",
            ToolName::KlodiTxConfirm => "klodi_tx_confirm",
            ToolName::KlodiTxCancel => "klodi_tx_cancel",
            ToolName::KlodiTxRate => "klodi_tx_rate",
            ToolName::KlodiTxStatus => "klodi_tx_status",
            ToolName::KlodiAssetsUploadUrl => "klodi_assets_upload_url",
        }
    }

    /// The NATS subject the marketplace handler listens on.
    pub fn subject(&self) -> &'static str {
        match self {
            ToolName::KlodiWhoami => "p2p.v1.users.whoami",
            ToolName::KlodiRatings => "p2p.v1.ratings.query",
            ToolName::KlodiListCreate => "p2p.v1.listings.create",
            ToolName::KlodiListUpdate => "p2p.v1.listings.update",
            ToolName::KlodiListGet => "p2p.v1.listings.get",
            ToolName::KlodiListMine => "p2p.v1.listings.mine",
            ToolName::KlodiListWithdraw => "p2p.v1.listings.update",
            ToolName::KlodiListRelist => "p2p.v1.listings.update",
            ToolName::KlodiListComments => "p2p.v1.comments.list",
            ToolName::KlodiSearch => "p2p.v1.listings.search",
            ToolName::KlodiSearchesCreate => "p2p.v1.searches.create",
            ToolName::KlodiSearchesDelete => "p2p.v1.searches.delete",
            ToolName::KlodiSearchesList => "p2p.v1.searches.list",
            ToolName::KlodiChannelCreate => "p2p.v1.channels.create",
            ToolName::KlodiChannelMine => "p2p.v1.channels.mine",
            ToolName::KlodiChannelHistory => "p2p.v1.channels.history",
            ToolName::KlodiChannelClose => "p2p.v1.channels.close",
            ToolName::KlodiComment => "p2p.v1.comments.create",
            ToolName::KlodiOfferCreate => "p2p.v1.offers.create",
            ToolName::KlodiOfferRespond => "p2p.v1.offers.respond",
            ToolName::KlodiOfferMine => "p2p.v1.offers.mine",
            ToolName::KlodiTxConfirm => "p2p.v1.transactions.confirm",
            ToolName::KlodiTxCancel => "p2p.v1.transactions.cancel",
            ToolName::KlodiTxRate => "p2p.v1.transactions.rate",
            ToolName::KlodiTxStatus => "p2p.v1.transactions.status",
            ToolName::KlodiAssetsUploadUrl => "p2p.v1.assets.upload-url",
        }
    }

    /// Parse from the public tool name.
    pub fn from_name(name: &str) -> Option<Self> {
        match name {
            "klodi_whoami" => Some(ToolName::KlodiWhoami),
            "klodi_ratings" => Some(ToolName::KlodiRatings),
            "klodi_list_create" => Some(ToolName::KlodiListCreate),
            "klodi_list_update" => Some(ToolName::KlodiListUpdate),
            "klodi_list_get" => Some(ToolName::KlodiListGet),
            "klodi_list_mine" => Some(ToolName::KlodiListMine),
            "klodi_list_withdraw" => Some(ToolName::KlodiListWithdraw),
            "klodi_list_relist" => Some(ToolName::KlodiListRelist),
            "klodi_list_comments" => Some(ToolName::KlodiListComments),
            "klodi_search" => Some(ToolName::KlodiSearch),
            "klodi_searches_create" => Some(ToolName::KlodiSearchesCreate),
            "klodi_searches_delete" => Some(ToolName::KlodiSearchesDelete),
            "klodi_searches_list" => Some(ToolName::KlodiSearchesList),
            "klodi_channel_create" => Some(ToolName::KlodiChannelCreate),
            "klodi_channel_mine" => Some(ToolName::KlodiChannelMine),
            "klodi_channel_history" => Some(ToolName::KlodiChannelHistory),
            "klodi_channel_close" => Some(ToolName::KlodiChannelClose),
            "klodi_comment" => Some(ToolName::KlodiComment),
            "klodi_offer_create" => Some(ToolName::KlodiOfferCreate),
            "klodi_offer_respond" => Some(ToolName::KlodiOfferRespond),
            "klodi_offer_mine" => Some(ToolName::KlodiOfferMine),
            "klodi_tx_confirm" => Some(ToolName::KlodiTxConfirm),
            "klodi_tx_cancel" => Some(ToolName::KlodiTxCancel),
            "klodi_tx_rate" => Some(ToolName::KlodiTxRate),
            "klodi_tx_status" => Some(ToolName::KlodiTxStatus),
            "klodi_assets_upload_url" => Some(ToolName::KlodiAssetsUploadUrl),
            _ => None,
        }
    }
}

// ─── Logging contract (D15) ───────────────────────────────────────────
/// Cross-language logging contract: levels, redact list, required-field
/// map. The `klodi-logger` Rust crate consumes these constants to honor
/// the contract test in `tests/integration/log-contract.test.ts`.
pub mod logging {
    /// Ordered log levels. Lower index = noisier.
    #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
    pub enum LogLevel {
        Debug,
        Info,
        Warn,
        Error,
    }

    impl LogLevel {
        pub fn as_str(&self) -> &'static str {
            match self {
                LogLevel::Debug => "DEBUG",
                LogLevel::Info => "INFO",
                LogLevel::Warn => "WARN",
                LogLevel::Error => "ERROR",
            }
        }

        /// Parse from the wire string form. Named `parse_str` (not
        /// `from_str`) to avoid shadowing `std::str::FromStr::from_str`.
        pub fn parse_str(s: &str) -> Option<Self> {
            match s {
                "DEBUG" => Some(LogLevel::Debug),
                "INFO" => Some(LogLevel::Info),
                "WARN" => Some(LogLevel::Warn),
                "ERROR" => Some(LogLevel::Error),
                _ => None,
            }
        }

        pub fn rank(&self) -> u8 {
            match self {
                LogLevel::Debug => 0,
                LogLevel::Info => 1,
                LogLevel::Warn => 2,
                LogLevel::Error => 3,
            }
        }
    }

    pub const LOG_LEVELS: &[&str] = &["DEBUG", "INFO", "WARN", "ERROR"];

    /// Field names whose values are replaced with REDACTION_PLACEHOLDER
    /// at INFO/WARN/ERROR. DEBUG bypasses redaction.
    pub const REDACTED_FIELD_NAMES: &[&str] = &["creds", "nkey_seed", "nkey_private", "authorization", "bearer_token", "min_acceptable_price", "auto_reject_below", "email", "bio", "avatar_url", "phone", "payload", "body", "content", "description", "terms", "stack_full"];

    pub const REDACTION_PLACEHOLDER: &str = "[redacted]";

    pub const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Info;

    /// Required fields per call-site type. Caller-side discipline; the
    /// integration contract test asserts presence at INFO.
    pub fn required_fields_by_site(site: &str) -> Option<&'static [&'static str]> {
        match site {
            "wake_handler" => Some(&["event_id", "kind"]),
            "tool_call_success" => Some(&["tool_name", "user_id", "latency_ms"]),
            "outbox_publish" => Some(&["event_id", "recipient_count", "attempt"]),
            "side_consumer_reject" => Some(&["user_id", "channel_id", "count_in_window"]),
            _ => None,
        }
    }

    /// Every recognised call-site type name.
    pub const CALL_SITE_TYPES: &[&str] = &["wake_handler", "tool_call_success", "outbox_publish", "side_consumer_reject"];
}

// ─── Local-only tools (D4) ────────────────────────────────────────────
/// Local-only tools that don't map 1:1 to a NATS subject.
/// Daemon-shape Rust hosts get the empty allowlist for `Daemon`.
///
/// `dead_code`: the daemon-shape adapters (Moltis / IronClaw / ZeroClaw)
/// import this crate but do not register any local tools (their
/// `for_host_shape(Daemon)` allowlist is empty), so the helper functions
/// look unused per-crate. They are part of the cross-language contract
/// surface and are exercised by `tests/integration/cross-language-wire`.
#[allow(dead_code)]
pub mod local_tools {
    /// Adapter shape declared in each adapter's host spec section 2.
    #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
    pub enum HostShape {
        InAgent,
        Daemon,
        CliOnly,
    }

    impl HostShape {
        pub fn as_str(&self) -> &'static str {
            match self {
                HostShape::InAgent => "in_agent",
                HostShape::Daemon => "daemon",
                HostShape::CliOnly => "cli_only",
            }
        }

        /// Parse from the wire string form. Named `parse_str` (not
        /// `from_str`) so it doesn't shadow `std::str::FromStr::from_str` —
        /// clippy's `should_implement_trait` lint enforces this distinction.
        pub fn parse_str(s: &str) -> Option<Self> {
            match s {
                "in_agent" => Some(HostShape::InAgent),
                "daemon" => Some(HostShape::Daemon),
                "cli_only" => Some(HostShape::CliOnly),
                _ => None,
            }
        }
    }

    pub const LOCAL_TOOL_NAMES: &[&str] = &["klodi_register", "klodi_register_poll", "klodi_health", "klodi_watch", "klodi_unwatch", "klodi_setup_status", "klodi_setup_repair", "klodi_setup_reseed_policies", "klodi_setup_reseed_skill", "klodi_channel_message"];

    /// Returns the declared host_shapes for a local tool name.
    pub fn host_shapes_for(name: &str) -> Option<&'static [&'static str]> {
        match name {
            "klodi_register" => Some(&["in_agent"]),
            "klodi_register_poll" => Some(&["in_agent"]),
            "klodi_health" => Some(&["in_agent"]),
            "klodi_watch" => Some(&["in_agent"]),
            "klodi_unwatch" => Some(&["in_agent"]),
            "klodi_setup_status" => Some(&["in_agent", "cli_only"]),
            "klodi_setup_repair" => Some(&["in_agent"]),
            "klodi_setup_reseed_policies" => Some(&["in_agent"]),
            "klodi_setup_reseed_skill" => Some(&["in_agent"]),
            "klodi_channel_message" => Some(&["in_agent"]),
            _ => None,
        }
    }

    /// Tool names an adapter with `shape` MUST register.
    pub fn for_host_shape(shape: HostShape) -> &'static [&'static str] {
        match shape {
            HostShape::InAgent => &["klodi_register", "klodi_register_poll", "klodi_health", "klodi_watch", "klodi_unwatch", "klodi_setup_status", "klodi_setup_repair", "klodi_setup_reseed_policies", "klodi_setup_reseed_skill", "klodi_channel_message"],
            HostShape::Daemon => &[],
            HostShape::CliOnly => &["klodi_setup_status"],
        }
    }
}
