//! Static X API endpoint definitions — the spec pack.
//!
//! Each `EndpointDef` maps one X API v2 (or v1.1) endpoint to an MCP tool.
//! Only *new* endpoints are defined here — the 29 curated Layer 1 tools
//! already exist in `manifest.rs` and are not duplicated.

use crate::contract::error_code::ErrorCode;
use crate::tools::manifest::{Profile, ToolCategory};

use super::params::{EndpointDef, HttpMethod, ParamDef, ParamType};

// ── Profile shorthands ─────────────────────────────────────────────────

/// All six profiles (original four + utility pair).
const ALL_SIX: &[Profile] = &[
    Profile::Readonly,
    Profile::ApiReadonly,
    Profile::Write,
    Profile::Admin,
    Profile::UtilityReadonly,
    Profile::UtilityWrite,
];
/// Write + Admin + ApiReadonly + UtilityWrite.
const WRITE_UP_AND_API_RO_AND_UTIL_WRITE: &[Profile] = &[
    Profile::ApiReadonly,
    Profile::Write,
    Profile::Admin,
    Profile::UtilityWrite,
];
/// Write + Admin + UtilityWrite.
const WRITE_UP_AND_UTIL_WRITE: &[Profile] =
    &[Profile::Write, Profile::Admin, Profile::UtilityWrite];
/// Admin profile only (enterprise/elevated-access tools).
const ADMIN_ONLY: &[Profile] = &[Profile::Admin];

// ── Error code sets ────────────────────────────────────────────────────

const X_READ_ERR: &[ErrorCode] = &[
    ErrorCode::XNotConfigured,
    ErrorCode::XRateLimited,
    ErrorCode::XAuthExpired,
    ErrorCode::XForbidden,
    ErrorCode::XNetworkError,
    ErrorCode::XApiError,
];

const X_WRITE_ERR: &[ErrorCode] = &[
    ErrorCode::XNotConfigured,
    ErrorCode::XRateLimited,
    ErrorCode::XAuthExpired,
    ErrorCode::XForbidden,
    ErrorCode::XNetworkError,
    ErrorCode::XApiError,
    ErrorCode::ScraperMutationBlocked,
    ErrorCode::PolicyDeniedBlocked,
    ErrorCode::PolicyDeniedRateLimited,
    ErrorCode::PolicyDeniedHardRule,
    ErrorCode::PolicyDeniedUserRule,
    ErrorCode::PolicyError,
];

// ── Common parameter definitions ───────────────────────────────────────

const PARAM_ID: ParamDef = ParamDef {
    name: "id",
    param_type: ParamType::String,
    required: true,
    description: "Resource ID",
    default: None,
};

const PARAM_USER_ID: ParamDef = ParamDef {
    name: "user_id",
    param_type: ParamType::String,
    required: true,
    description: "User ID (authenticated user for /me endpoints)",
    default: None,
};

const PARAM_TARGET_USER_ID: ParamDef = ParamDef {
    name: "target_user_id",
    param_type: ParamType::String,
    required: true,
    description: "Target user ID",
    default: None,
};

const PARAM_MAX_RESULTS: ParamDef = ParamDef {
    name: "max_results",
    param_type: ParamType::Integer,
    required: false,
    description: "Maximum number of results to return",
    default: Some("100"),
};

const PARAM_PAGINATION_TOKEN: ParamDef = ParamDef {
    name: "pagination_token",
    param_type: ParamType::String,
    required: false,
    description: "Token for paginating through results",
    default: None,
};

const PARAM_TWEET_FIELDS: ParamDef = ParamDef {
    name: "tweet_fields",
    param_type: ParamType::StringArray,
    required: false,
    description: "Comma-separated tweet fields to include (e.g. created_at,public_metrics)",
    default: None,
};

const PARAM_USER_FIELDS: ParamDef = ParamDef {
    name: "user_fields",
    param_type: ParamType::StringArray,
    required: false,
    description: "Comma-separated user fields to include (e.g. created_at,public_metrics)",
    default: None,
};

const PARAM_EXPANSIONS: ParamDef = ParamDef {
    name: "expansions",
    param_type: ParamType::StringArray,
    required: false,
    description: "Comma-separated expansions (e.g. author_id,referenced_tweets.id)",
    default: None,
};

const PARAM_LIST_FIELDS: ParamDef = ParamDef {
    name: "list_fields",
    param_type: ParamType::StringArray,
    required: false,
    description: "Comma-separated list fields (e.g. created_at,member_count,owner_id)",
    default: None,
};

const PARAM_SPACE_FIELDS: ParamDef = ParamDef {
    name: "space_fields",
    param_type: ParamType::StringArray,
    required: false,
    description: "Comma-separated space fields (e.g. host_ids,title,state)",
    default: None,
};

const PARAM_DM_EVENT_FIELDS: ParamDef = ParamDef {
    name: "dm_event_fields",
    param_type: ParamType::StringArray,
    required: false,
    description: "Comma-separated DM event fields (e.g. id,text,event_type,created_at,sender_id)",
    default: None,
};

const PARAM_PARTICIPANT_ID: ParamDef = ParamDef {
    name: "participant_id",
    param_type: ParamType::String,
    required: true,
    description: "User ID of the DM conversation participant",
    default: None,
};

// ── Ads-specific parameter definitions ────────────────────────────────

const PARAM_ACCOUNT_ID: ParamDef = ParamDef {
    name: "account_id",
    param_type: ParamType::String,
    required: true,
    description: "Ads account ID",
    default: None,
};

const PARAM_CAMPAIGN_ID: ParamDef = ParamDef {
    name: "campaign_id",
    param_type: ParamType::String,
    required: true,
    description: "Campaign ID",
    default: None,
};

const PARAM_WITH_DELETED: ParamDef = ParamDef {
    name: "with_deleted",
    param_type: ParamType::Boolean,
    required: false,
    description: "Include deleted entities in the response",
    default: Some("false"),
};

const PARAM_ADS_CURSOR: ParamDef = ParamDef {
    name: "cursor",
    param_type: ParamType::String,
    required: false,
    description: "Cursor for paginating through Ads API results",
    default: None,
};

const PARAM_ADS_COUNT: ParamDef = ParamDef {
    name: "count",
    param_type: ParamType::Integer,
    required: false,
    description: "Number of results per page (Ads API, default: 200)",
    default: Some("200"),
};

// ── Compliance-specific parameter definitions ─────────────────────────

const PARAM_COMPLIANCE_TYPE: ParamDef = ParamDef {
    name: "type",
    param_type: ParamType::String,
    required: true,
    description: "Compliance job type: tweets or users",
    default: None,
};

const PARAM_COMPLIANCE_STATUS: ParamDef = ParamDef {
    name: "status",
    param_type: ParamType::String,
    required: false,
    description: "Filter jobs by status: created, in_progress, complete, expired, failed",
    default: None,
};

const PARAM_USAGE_DAYS: ParamDef = ParamDef {
    name: "days",
    param_type: ParamType::Integer,
    required: false,
    description: "Number of days of usage data to retrieve (default: 7)",
    default: Some("7"),
};

const PARAM_STREAM_RULE_VALUE: ParamDef = ParamDef {
    name: "value",
    param_type: ParamType::String,
    required: true,
    description: "The stream rule filter expression (e.g. 'cat has:images')",
    default: None,
};

const PARAM_STREAM_RULE_TAG: ParamDef = ParamDef {
    name: "tag",
    param_type: ParamType::String,
    required: false,
    description: "Optional label/tag for the stream rule",
    default: None,
};

const PARAM_STREAM_RULE_IDS: ParamDef = ParamDef {
    name: "rule_ids",
    param_type: ParamType::StringArray,
    required: true,
    description: "Comma-separated rule IDs to delete",
    default: None,
};

// ── The spec pack ──────────────────────────────────────────────────────

/// All X API endpoint definitions in the spec pack.
///
/// Sorted alphabetically by `tool_name` for deterministic output.
/// Only new endpoints — existing curated tools are not duplicated.
pub static SPEC_ENDPOINTS: &[EndpointDef] = &[
    // ── Batch Lookups (3) ──────────────────────────────────────────
    EndpointDef {
        tool_name: "x_v2_tweets_lookup",
        description: "Look up multiple tweets by their IDs in a single request",
        method: HttpMethod::Get,
        path: "/2/tweets",
        category: ToolCategory::Read,
        profiles: ALL_SIX,
        scopes: &["tweet.read", "users.read"],
        params: &[
            ParamDef {
                name: "ids",
                param_type: ParamType::StringArray,
                required: true,
                description: "Comma-separated tweet IDs (up to 100)",
                default: None,
            },
            PARAM_TWEET_FIELDS,
            PARAM_USER_FIELDS,
            PARAM_EXPANSIONS,
        ],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "tweets",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_users_lookup_by_usernames",
        description: "Look up multiple users by their usernames in a single request",
        method: HttpMethod::Get,
        path: "/2/users/by",
        category: ToolCategory::Read,
        profiles: ALL_SIX,
        scopes: &["users.read"],
        params: &[
            ParamDef {
                name: "usernames",
                param_type: ParamType::StringArray,
                required: true,
                description: "Comma-separated usernames (up to 100, without @ prefix)",
                default: None,
            },
            PARAM_USER_FIELDS,
            PARAM_EXPANSIONS,
        ],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "users",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_tweets_retweeted_by",
        description: "Get users who retweeted a specific tweet",
        method: HttpMethod::Get,
        path: "/2/tweets/{id}/retweeted_by",
        category: ToolCategory::Read,
        profiles: ALL_SIX,
        scopes: &["tweet.read", "users.read"],
        params: &[
            PARAM_ID,
            PARAM_MAX_RESULTS,
            PARAM_PAGINATION_TOKEN,
            PARAM_USER_FIELDS,
        ],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "tweets",
        host: None,
    },
    // ── Tweet Metadata (4) ─────────────────────────────────────────
    EndpointDef {
        tool_name: "x_v2_tweets_quote_tweets",
        description: "Get tweets that quote a specific tweet",
        method: HttpMethod::Get,
        path: "/2/tweets/{id}/quote_tweets",
        category: ToolCategory::Read,
        profiles: ALL_SIX,
        scopes: &["tweet.read", "users.read"],
        params: &[
            PARAM_ID,
            PARAM_MAX_RESULTS,
            PARAM_PAGINATION_TOKEN,
            PARAM_TWEET_FIELDS,
            PARAM_USER_FIELDS,
            PARAM_EXPANSIONS,
        ],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "tweets",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_tweets_counts_recent",
        description: "Get count of tweets matching a query from the last 7 days",
        method: HttpMethod::Get,
        path: "/2/tweets/counts/recent",
        category: ToolCategory::Read,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["tweet.read"],
        params: &[
            ParamDef {
                name: "query",
                param_type: ParamType::String,
                required: true,
                description: "Search query (same syntax as search/recent)",
                default: None,
            },
            ParamDef {
                name: "granularity",
                param_type: ParamType::String,
                required: false,
                description: "Aggregation granularity: minute, hour, or day",
                default: Some("hour"),
            },
            ParamDef {
                name: "start_time",
                param_type: ParamType::String,
                required: false,
                description: "Start time in ISO 8601 format",
                default: None,
            },
            ParamDef {
                name: "end_time",
                param_type: ParamType::String,
                required: false,
                description: "End time in ISO 8601 format",
                default: None,
            },
        ],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "tweets",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_tweets_hide_reply",
        description: "Hide a reply to one of your tweets",
        method: HttpMethod::Put,
        path: "/2/tweets/{id}/hidden",
        category: ToolCategory::Moderation,
        profiles: WRITE_UP_AND_UTIL_WRITE,
        scopes: &["tweet.read", "tweet.moderate.write"],
        params: &[
            PARAM_ID,
            ParamDef {
                name: "hidden",
                param_type: ParamType::Boolean,
                required: true,
                description: "Set to true to hide, false to unhide",
                default: None,
            },
        ],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "tweets",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_tweets_unhide_reply",
        description: "Unhide a previously hidden reply",
        method: HttpMethod::Put,
        path: "/2/tweets/{id}/hidden",
        category: ToolCategory::Moderation,
        profiles: WRITE_UP_AND_UTIL_WRITE,
        scopes: &["tweet.read", "tweet.moderate.write"],
        params: &[
            PARAM_ID,
            ParamDef {
                name: "hidden",
                param_type: ParamType::Boolean,
                required: true,
                description: "Set to false to unhide",
                default: None,
            },
        ],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "tweets",
        host: None,
    },
    // ── Pin Management (2) ─────────────────────────────────────────
    EndpointDef {
        tool_name: "x_v2_users_pin_tweet",
        description: "Pin a tweet to your profile",
        method: HttpMethod::Put,
        path: "/2/users/{user_id}/pinned_tweet",
        category: ToolCategory::Engage,
        profiles: WRITE_UP_AND_UTIL_WRITE,
        scopes: &["tweet.read", "users.read", "tweet.write"],
        params: &[
            PARAM_USER_ID,
            ParamDef {
                name: "tweet_id",
                param_type: ParamType::String,
                required: true,
                description: "ID of the tweet to pin",
                default: None,
            },
        ],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "users",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_users_unpin_tweet",
        description: "Unpin a tweet from your profile",
        method: HttpMethod::Delete,
        path: "/2/users/{user_id}/pinned_tweet",
        category: ToolCategory::Engage,
        profiles: WRITE_UP_AND_UTIL_WRITE,
        scopes: &["tweet.read", "users.read", "tweet.write"],
        params: &[PARAM_USER_ID],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "users",
        host: None,
    },
    // ── Lists (15) ─────────────────────────────────────────────────
    EndpointDef {
        tool_name: "x_v2_lists_get",
        description: "Look up a list by its ID",
        method: HttpMethod::Get,
        path: "/2/lists/{id}",
        category: ToolCategory::List,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["list.read"],
        params: &[PARAM_ID, PARAM_LIST_FIELDS, PARAM_EXPANSIONS],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "lists",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_lists_owned",
        description: "Get lists owned by a user",
        method: HttpMethod::Get,
        path: "/2/users/{user_id}/owned_lists",
        category: ToolCategory::List,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["list.read", "users.read"],
        params: &[
            PARAM_USER_ID,
            PARAM_MAX_RESULTS,
            PARAM_PAGINATION_TOKEN,
            PARAM_LIST_FIELDS,
        ],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "lists",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_lists_create",
        description: "Create a new list",
        method: HttpMethod::Post,
        path: "/2/lists",
        category: ToolCategory::List,
        profiles: WRITE_UP_AND_UTIL_WRITE,
        scopes: &["list.write"],
        params: &[
            ParamDef {
                name: "name",
                param_type: ParamType::String,
                required: true,
                description: "Name of the list (max 25 characters)",
                default: None,
            },
            ParamDef {
                name: "description",
                param_type: ParamType::String,
                required: false,
                description: "Description of the list (max 100 characters)",
                default: None,
            },
            ParamDef {
                name: "private",
                param_type: ParamType::Boolean,
                required: false,
                description: "Whether the list is private",
                default: Some("false"),
            },
        ],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "lists",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_lists_update",
        description: "Update a list's name, description, or privacy setting",
        method: HttpMethod::Put,
        path: "/2/lists/{id}",
        category: ToolCategory::List,
        profiles: WRITE_UP_AND_UTIL_WRITE,
        scopes: &["list.write"],
        params: &[
            PARAM_ID,
            ParamDef {
                name: "name",
                param_type: ParamType::String,
                required: false,
                description: "New name for the list",
                default: None,
            },
            ParamDef {
                name: "description",
                param_type: ParamType::String,
                required: false,
                description: "New description for the list",
                default: None,
            },
            ParamDef {
                name: "private",
                param_type: ParamType::Boolean,
                required: false,
                description: "Whether the list is private",
                default: None,
            },
        ],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "lists",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_lists_delete",
        description: "Delete a list you own",
        method: HttpMethod::Delete,
        path: "/2/lists/{id}",
        category: ToolCategory::List,
        profiles: WRITE_UP_AND_UTIL_WRITE,
        scopes: &["list.write"],
        params: &[PARAM_ID],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "lists",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_lists_tweets",
        description: "Get tweets from a list's timeline",
        method: HttpMethod::Get,
        path: "/2/lists/{id}/tweets",
        category: ToolCategory::List,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["list.read", "tweet.read", "users.read"],
        params: &[
            PARAM_ID,
            PARAM_MAX_RESULTS,
            PARAM_PAGINATION_TOKEN,
            PARAM_TWEET_FIELDS,
            PARAM_USER_FIELDS,
            PARAM_EXPANSIONS,
        ],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "lists",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_lists_members",
        description: "Get members of a list",
        method: HttpMethod::Get,
        path: "/2/lists/{id}/members",
        category: ToolCategory::List,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["list.read", "users.read"],
        params: &[
            PARAM_ID,
            PARAM_MAX_RESULTS,
            PARAM_PAGINATION_TOKEN,
            PARAM_USER_FIELDS,
        ],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "lists",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_lists_members_add",
        description: "Add a user as a member of a list",
        method: HttpMethod::Post,
        path: "/2/lists/{id}/members",
        category: ToolCategory::List,
        profiles: WRITE_UP_AND_UTIL_WRITE,
        scopes: &["list.write", "users.read"],
        params: &[
            PARAM_ID,
            ParamDef {
                name: "user_id",
                param_type: ParamType::String,
                required: true,
                description: "User ID to add to the list",
                default: None,
            },
        ],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "lists",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_lists_members_remove",
        description: "Remove a user from a list",
        method: HttpMethod::Delete,
        path: "/2/lists/{id}/members/{user_id}",
        category: ToolCategory::List,
        profiles: WRITE_UP_AND_UTIL_WRITE,
        scopes: &["list.write", "users.read"],
        params: &[PARAM_ID, PARAM_TARGET_USER_ID],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "lists",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_lists_memberships",
        description: "Get lists a user is a member of",
        method: HttpMethod::Get,
        path: "/2/users/{user_id}/list_memberships",
        category: ToolCategory::List,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["list.read", "users.read"],
        params: &[
            PARAM_USER_ID,
            PARAM_MAX_RESULTS,
            PARAM_PAGINATION_TOKEN,
            PARAM_LIST_FIELDS,
        ],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "lists",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_lists_followers",
        description: "Get followers of a list",
        method: HttpMethod::Get,
        path: "/2/lists/{id}/followers",
        category: ToolCategory::List,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["list.read", "users.read"],
        params: &[
            PARAM_ID,
            PARAM_MAX_RESULTS,
            PARAM_PAGINATION_TOKEN,
            PARAM_USER_FIELDS,
        ],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "lists",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_lists_follow",
        description: "Follow a list",
        method: HttpMethod::Post,
        path: "/2/users/{user_id}/followed_lists",
        category: ToolCategory::List,
        profiles: WRITE_UP_AND_UTIL_WRITE,
        scopes: &["list.write", "users.read"],
        params: &[
            PARAM_USER_ID,
            ParamDef {
                name: "list_id",
                param_type: ParamType::String,
                required: true,
                description: "ID of the list to follow",
                default: None,
            },
        ],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "lists",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_lists_unfollow",
        description: "Unfollow a list",
        method: HttpMethod::Delete,
        path: "/2/users/{user_id}/followed_lists/{list_id}",
        category: ToolCategory::List,
        profiles: WRITE_UP_AND_UTIL_WRITE,
        scopes: &["list.write", "users.read"],
        params: &[
            PARAM_USER_ID,
            ParamDef {
                name: "list_id",
                param_type: ParamType::String,
                required: true,
                description: "ID of the list to unfollow",
                default: None,
            },
        ],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "lists",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_lists_pinned",
        description: "Get a user's pinned lists",
        method: HttpMethod::Get,
        path: "/2/users/{user_id}/pinned_lists",
        category: ToolCategory::List,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["list.read", "users.read"],
        params: &[PARAM_USER_ID, PARAM_LIST_FIELDS],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "lists",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_lists_pin",
        description: "Pin a list",
        method: HttpMethod::Post,
        path: "/2/users/{user_id}/pinned_lists",
        category: ToolCategory::List,
        profiles: WRITE_UP_AND_UTIL_WRITE,
        scopes: &["list.write", "users.read"],
        params: &[
            PARAM_USER_ID,
            ParamDef {
                name: "list_id",
                param_type: ParamType::String,
                required: true,
                description: "ID of the list to pin",
                default: None,
            },
        ],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "lists",
        host: None,
    },
    // ── Mutes (3) ──────────────────────────────────────────────────
    EndpointDef {
        tool_name: "x_v2_mutes_list",
        description: "Get users you have muted",
        method: HttpMethod::Get,
        path: "/2/users/{user_id}/muting",
        category: ToolCategory::Moderation,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["mute.read", "users.read"],
        params: &[
            PARAM_USER_ID,
            PARAM_MAX_RESULTS,
            PARAM_PAGINATION_TOKEN,
            PARAM_USER_FIELDS,
        ],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "mutes",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_mutes_create",
        description: "Mute a user",
        method: HttpMethod::Post,
        path: "/2/users/{user_id}/muting",
        category: ToolCategory::Moderation,
        profiles: WRITE_UP_AND_UTIL_WRITE,
        scopes: &["mute.write", "users.read"],
        params: &[
            PARAM_USER_ID,
            ParamDef {
                name: "target_user_id",
                param_type: ParamType::String,
                required: true,
                description: "ID of the user to mute",
                default: None,
            },
        ],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "mutes",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_mutes_delete",
        description: "Unmute a user",
        method: HttpMethod::Delete,
        path: "/2/users/{user_id}/muting/{target_user_id}",
        category: ToolCategory::Moderation,
        profiles: WRITE_UP_AND_UTIL_WRITE,
        scopes: &["mute.write", "users.read"],
        params: &[PARAM_USER_ID, PARAM_TARGET_USER_ID],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "mutes",
        host: None,
    },
    // ── Blocks (3) ─────────────────────────────────────────────────
    EndpointDef {
        tool_name: "x_v2_blocks_list",
        description: "Get users you have blocked",
        method: HttpMethod::Get,
        path: "/2/users/{user_id}/blocking",
        category: ToolCategory::Moderation,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["block.read", "users.read"],
        params: &[
            PARAM_USER_ID,
            PARAM_MAX_RESULTS,
            PARAM_PAGINATION_TOKEN,
            PARAM_USER_FIELDS,
        ],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "blocks",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_blocks_create",
        description: "Block a user",
        method: HttpMethod::Post,
        path: "/2/users/{user_id}/blocking",
        category: ToolCategory::Moderation,
        profiles: WRITE_UP_AND_UTIL_WRITE,
        scopes: &["block.write", "users.read"],
        params: &[
            PARAM_USER_ID,
            ParamDef {
                name: "target_user_id",
                param_type: ParamType::String,
                required: true,
                description: "ID of the user to block",
                default: None,
            },
        ],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "blocks",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_blocks_delete",
        description: "Unblock a user",
        method: HttpMethod::Delete,
        path: "/2/users/{user_id}/blocking/{target_user_id}",
        category: ToolCategory::Moderation,
        profiles: WRITE_UP_AND_UTIL_WRITE,
        scopes: &["block.write", "users.read"],
        params: &[PARAM_USER_ID, PARAM_TARGET_USER_ID],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "blocks",
        host: None,
    },
    // ── Spaces (6) ─────────────────────────────────────────────────
    EndpointDef {
        tool_name: "x_v2_spaces_get",
        description: "Look up a Space by its ID",
        method: HttpMethod::Get,
        path: "/2/spaces/{id}",
        category: ToolCategory::Read,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["space.read"],
        params: &[PARAM_ID, PARAM_SPACE_FIELDS, PARAM_EXPANSIONS],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "spaces",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_spaces_lookup",
        description: "Look up multiple Spaces by their IDs",
        method: HttpMethod::Get,
        path: "/2/spaces",
        category: ToolCategory::Read,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["space.read"],
        params: &[
            ParamDef {
                name: "ids",
                param_type: ParamType::StringArray,
                required: true,
                description: "Comma-separated Space IDs",
                default: None,
            },
            PARAM_SPACE_FIELDS,
            PARAM_EXPANSIONS,
        ],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "spaces",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_spaces_by_creator",
        description: "Get Spaces created by specific users",
        method: HttpMethod::Get,
        path: "/2/spaces/by/creator_ids",
        category: ToolCategory::Read,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["space.read", "users.read"],
        params: &[
            ParamDef {
                name: "user_ids",
                param_type: ParamType::StringArray,
                required: true,
                description: "Comma-separated user IDs of Space creators",
                default: None,
            },
            PARAM_SPACE_FIELDS,
            PARAM_EXPANSIONS,
        ],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "spaces",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_spaces_search",
        description: "Search for Spaces by title",
        method: HttpMethod::Get,
        path: "/2/spaces/search",
        category: ToolCategory::Read,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["space.read"],
        params: &[
            ParamDef {
                name: "query",
                param_type: ParamType::String,
                required: true,
                description: "Search query to find Spaces by title",
                default: None,
            },
            ParamDef {
                name: "state",
                param_type: ParamType::String,
                required: false,
                description: "Filter by state: live, scheduled, or all",
                default: Some("all"),
            },
            PARAM_SPACE_FIELDS,
            PARAM_EXPANSIONS,
        ],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "spaces",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_spaces_buyers",
        description: "Get users who purchased a ticket to a Space",
        method: HttpMethod::Get,
        path: "/2/spaces/{id}/buyers",
        category: ToolCategory::Read,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["space.read", "users.read"],
        params: &[PARAM_ID, PARAM_USER_FIELDS],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "spaces",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_spaces_tweets",
        description: "Get tweets shared in a Space",
        method: HttpMethod::Get,
        path: "/2/spaces/{id}/tweets",
        category: ToolCategory::Read,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["space.read", "tweet.read", "users.read"],
        params: &[
            PARAM_ID,
            PARAM_TWEET_FIELDS,
            PARAM_USER_FIELDS,
            PARAM_EXPANSIONS,
        ],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "spaces",
        host: None,
    },
    // ── Direct Messages (8) ───────────────────────────────────────
    EndpointDef {
        tool_name: "x_v2_dm_conversations",
        description: "List DM conversations for the authenticated user",
        method: HttpMethod::Get,
        path: "/2/dm_conversations",
        category: ToolCategory::DirectMessage,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["dm.read", "users.read"],
        params: &[
            PARAM_MAX_RESULTS,
            PARAM_PAGINATION_TOKEN,
            PARAM_DM_EVENT_FIELDS,
            PARAM_EXPANSIONS,
        ],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "direct_messages",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_dm_conversation_by_id",
        description: "Look up a DM conversation by its ID",
        method: HttpMethod::Get,
        path: "/2/dm_conversations/{id}",
        category: ToolCategory::DirectMessage,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["dm.read", "users.read"],
        params: &[PARAM_ID, PARAM_DM_EVENT_FIELDS, PARAM_EXPANSIONS],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "direct_messages",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_dm_events_by_conversation",
        description: "Get DM events (messages) in a specific conversation",
        method: HttpMethod::Get,
        path: "/2/dm_conversations/{id}/dm_events",
        category: ToolCategory::DirectMessage,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["dm.read", "users.read"],
        params: &[
            PARAM_ID,
            PARAM_MAX_RESULTS,
            PARAM_PAGINATION_TOKEN,
            PARAM_DM_EVENT_FIELDS,
            PARAM_EXPANSIONS,
        ],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "direct_messages",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_dm_events_by_participant",
        description: "Get DM events with a specific participant",
        method: HttpMethod::Get,
        path: "/2/dm_conversations/with/{participant_id}/dm_events",
        category: ToolCategory::DirectMessage,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["dm.read", "users.read"],
        params: &[
            PARAM_PARTICIPANT_ID,
            PARAM_MAX_RESULTS,
            PARAM_PAGINATION_TOKEN,
            PARAM_DM_EVENT_FIELDS,
            PARAM_EXPANSIONS,
        ],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "direct_messages",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_dm_events",
        description: "List all recent DM events across conversations",
        method: HttpMethod::Get,
        path: "/2/dm_events",
        category: ToolCategory::DirectMessage,
        profiles: WRITE_UP_AND_API_RO_AND_UTIL_WRITE,
        scopes: &["dm.read", "users.read"],
        params: &[
            PARAM_MAX_RESULTS,
            PARAM_PAGINATION_TOKEN,
            PARAM_DM_EVENT_FIELDS,
            PARAM_EXPANSIONS,
        ],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "direct_messages",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_dm_send_in_conversation",
        description: "Send a DM message in an existing conversation",
        method: HttpMethod::Post,
        path: "/2/dm_conversations/{id}/messages",
        category: ToolCategory::DirectMessage,
        profiles: WRITE_UP_AND_UTIL_WRITE,
        scopes: &["dm.write", "dm.read", "users.read"],
        params: &[
            PARAM_ID,
            ParamDef {
                name: "text",
                param_type: ParamType::String,
                required: true,
                description: "The message text to send",
                default: None,
            },
            ParamDef {
                name: "attachments",
                param_type: ParamType::StringArray,
                required: false,
                description: "Comma-separated media IDs to attach",
                default: None,
            },
        ],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "direct_messages",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_dm_send_to_participant",
        description: "Send a DM message to a specific user (creates 1-on-1 conversation)",
        method: HttpMethod::Post,
        path: "/2/dm_conversations/with/{participant_id}/messages",
        category: ToolCategory::DirectMessage,
        profiles: WRITE_UP_AND_UTIL_WRITE,
        scopes: &["dm.write", "dm.read", "users.read"],
        params: &[
            PARAM_PARTICIPANT_ID,
            ParamDef {
                name: "text",
                param_type: ParamType::String,
                required: true,
                description: "The message text to send",
                default: None,
            },
            ParamDef {
                name: "attachments",
                param_type: ParamType::StringArray,
                required: false,
                description: "Comma-separated media IDs to attach",
                default: None,
            },
        ],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "direct_messages",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_dm_create_group",
        description: "Create a new group DM conversation with an initial message",
        method: HttpMethod::Post,
        path: "/2/dm_conversations",
        category: ToolCategory::DirectMessage,
        profiles: WRITE_UP_AND_UTIL_WRITE,
        scopes: &["dm.write", "dm.read", "users.read"],
        params: &[
            ParamDef {
                name: "participant_ids",
                param_type: ParamType::StringArray,
                required: true,
                description: "Comma-separated user IDs of group participants",
                default: None,
            },
            ParamDef {
                name: "text",
                param_type: ParamType::String,
                required: true,
                description: "The initial message text for the group conversation",
                default: None,
            },
            ParamDef {
                name: "attachments",
                param_type: ParamType::StringArray,
                required: false,
                description: "Comma-separated media IDs to attach",
                default: None,
            },
        ],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "direct_messages",
        host: None,
    },
    // ── Ads / Campaign (16) — Admin-only, host: ads-api.x.com ─────
    EndpointDef {
        tool_name: "x_ads_accounts",
        description: "List all advertising accounts the authenticating user has access to",
        method: HttpMethod::Get,
        path: "/12/accounts",
        category: ToolCategory::Ads,
        profiles: ADMIN_ONLY,
        scopes: &["ads.read"],
        params: &[PARAM_WITH_DELETED, PARAM_ADS_CURSOR, PARAM_ADS_COUNT],
        error_codes: X_READ_ERR,
        api_version: "ads-v12",
        group: "ads",
        host: Some("ads-api.x.com"),
    },
    EndpointDef {
        tool_name: "x_ads_account_by_id",
        description: "Get details of a specific advertising account",
        method: HttpMethod::Get,
        path: "/12/accounts/{account_id}",
        category: ToolCategory::Ads,
        profiles: ADMIN_ONLY,
        scopes: &["ads.read"],
        params: &[PARAM_ACCOUNT_ID, PARAM_WITH_DELETED],
        error_codes: X_READ_ERR,
        api_version: "ads-v12",
        group: "ads",
        host: Some("ads-api.x.com"),
    },
    EndpointDef {
        tool_name: "x_ads_analytics",
        description: "Retrieve analytics and performance metrics for an ads account",
        method: HttpMethod::Get,
        path: "/12/stats/accounts/{account_id}",
        category: ToolCategory::Ads,
        profiles: ADMIN_ONLY,
        scopes: &["ads.read"],
        params: &[
            PARAM_ACCOUNT_ID,
            ParamDef {
                name: "entity",
                param_type: ParamType::String,
                required: false,
                description: "Entity type: CAMPAIGN, LINE_ITEM, PROMOTED_TWEET",
                default: None,
            },
            ParamDef {
                name: "entity_ids",
                param_type: ParamType::StringArray,
                required: false,
                description: "Comma-separated entity IDs to retrieve metrics for",
                default: None,
            },
            ParamDef {
                name: "start_time",
                param_type: ParamType::String,
                required: false,
                description: "Start time in ISO 8601 format",
                default: None,
            },
            ParamDef {
                name: "end_time",
                param_type: ParamType::String,
                required: false,
                description: "End time in ISO 8601 format",
                default: None,
            },
            ParamDef {
                name: "granularity",
                param_type: ParamType::String,
                required: false,
                description: "Aggregation granularity: HOUR, DAY, TOTAL",
                default: Some("DAY"),
            },
            ParamDef {
                name: "metric_groups",
                param_type: ParamType::StringArray,
                required: false,
                description: "Comma-separated metric groups (e.g. ENGAGEMENT,BILLING)",
                default: None,
            },
        ],
        error_codes: X_READ_ERR,
        api_version: "ads-v12",
        group: "ads",
        host: Some("ads-api.x.com"),
    },
    EndpointDef {
        tool_name: "x_ads_campaign_by_id",
        description: "Get details of a specific campaign",
        method: HttpMethod::Get,
        path: "/12/accounts/{account_id}/campaigns/{campaign_id}",
        category: ToolCategory::Ads,
        profiles: ADMIN_ONLY,
        scopes: &["ads.read"],
        params: &[PARAM_ACCOUNT_ID, PARAM_CAMPAIGN_ID, PARAM_WITH_DELETED],
        error_codes: X_READ_ERR,
        api_version: "ads-v12",
        group: "ads",
        host: Some("ads-api.x.com"),
    },
    EndpointDef {
        tool_name: "x_ads_campaign_create",
        description: "Create a new advertising campaign",
        method: HttpMethod::Post,
        path: "/12/accounts/{account_id}/campaigns",
        category: ToolCategory::Ads,
        profiles: ADMIN_ONLY,
        scopes: &["ads.read", "ads.write"],
        params: &[
            PARAM_ACCOUNT_ID,
            ParamDef {
                name: "name",
                param_type: ParamType::String,
                required: true,
                description: "Campaign name",
                default: None,
            },
            ParamDef {
                name: "funding_instrument_id",
                param_type: ParamType::String,
                required: true,
                description: "Funding instrument ID for the campaign budget",
                default: None,
            },
            ParamDef {
                name: "status",
                param_type: ParamType::String,
                required: false,
                description: "Campaign status: ACTIVE, PAUSED, DRAFT",
                default: Some("PAUSED"),
            },
            ParamDef {
                name: "daily_budget_amount_local_micro",
                param_type: ParamType::Integer,
                required: false,
                description: "Daily budget in microcurrency units (e.g. 5000000 = $5.00)",
                default: None,
            },
            ParamDef {
                name: "start_time",
                param_type: ParamType::String,
                required: false,
                description: "Campaign start time in ISO 8601 format",
                default: None,
            },
            ParamDef {
                name: "end_time",
                param_type: ParamType::String,
                required: false,
                description: "Campaign end time in ISO 8601 format",
                default: None,
            },
        ],
        error_codes: X_WRITE_ERR,
        api_version: "ads-v12",
        group: "ads",
        host: Some("ads-api.x.com"),
    },
    EndpointDef {
        tool_name: "x_ads_campaign_delete",
        description: "Delete (archive) a campaign",
        method: HttpMethod::Delete,
        path: "/12/accounts/{account_id}/campaigns/{campaign_id}",
        category: ToolCategory::Ads,
        profiles: ADMIN_ONLY,
        scopes: &["ads.read", "ads.write"],
        params: &[PARAM_ACCOUNT_ID, PARAM_CAMPAIGN_ID],
        error_codes: X_WRITE_ERR,
        api_version: "ads-v12",
        group: "ads",
        host: Some("ads-api.x.com"),
    },
    EndpointDef {
        tool_name: "x_ads_campaign_update",
        description: "Update an existing campaign's name, status, or budget",
        method: HttpMethod::Put,
        path: "/12/accounts/{account_id}/campaigns/{campaign_id}",
        category: ToolCategory::Ads,
        profiles: ADMIN_ONLY,
        scopes: &["ads.read", "ads.write"],
        params: &[
            PARAM_ACCOUNT_ID,
            PARAM_CAMPAIGN_ID,
            ParamDef {
                name: "name",
                param_type: ParamType::String,
                required: false,
                description: "Updated campaign name",
                default: None,
            },
            ParamDef {
                name: "status",
                param_type: ParamType::String,
                required: false,
                description: "Updated status: ACTIVE, PAUSED",
                default: None,
            },
            ParamDef {
                name: "daily_budget_amount_local_micro",
                param_type: ParamType::Integer,
                required: false,
                description: "Updated daily budget in microcurrency units",
                default: None,
            },
            ParamDef {
                name: "start_time",
                param_type: ParamType::String,
                required: false,
                description: "Updated start time in ISO 8601 format",
                default: None,
            },
            ParamDef {
                name: "end_time",
                param_type: ParamType::String,
                required: false,
                description: "Updated end time in ISO 8601 format",
                default: None,
            },
        ],
        error_codes: X_WRITE_ERR,
        api_version: "ads-v12",
        group: "ads",
        host: Some("ads-api.x.com"),
    },
    EndpointDef {
        tool_name: "x_ads_campaigns",
        description: "List campaigns for an advertising account",
        method: HttpMethod::Get,
        path: "/12/accounts/{account_id}/campaigns",
        category: ToolCategory::Ads,
        profiles: ADMIN_ONLY,
        scopes: &["ads.read"],
        params: &[
            PARAM_ACCOUNT_ID,
            ParamDef {
                name: "campaign_ids",
                param_type: ParamType::StringArray,
                required: false,
                description: "Comma-separated campaign IDs to filter by",
                default: None,
            },
            PARAM_WITH_DELETED,
            PARAM_ADS_CURSOR,
            PARAM_ADS_COUNT,
        ],
        error_codes: X_READ_ERR,
        api_version: "ads-v12",
        group: "ads",
        host: Some("ads-api.x.com"),
    },
    EndpointDef {
        tool_name: "x_ads_funding_instruments",
        description: "List funding instruments (payment methods) for an ads account",
        method: HttpMethod::Get,
        path: "/12/accounts/{account_id}/funding_instruments",
        category: ToolCategory::Ads,
        profiles: ADMIN_ONLY,
        scopes: &["ads.read"],
        params: &[
            PARAM_ACCOUNT_ID,
            PARAM_WITH_DELETED,
            PARAM_ADS_CURSOR,
            PARAM_ADS_COUNT,
        ],
        error_codes: X_READ_ERR,
        api_version: "ads-v12",
        group: "ads",
        host: Some("ads-api.x.com"),
    },
    EndpointDef {
        tool_name: "x_ads_line_item_create",
        description: "Create a new line item (ad group) within a campaign",
        method: HttpMethod::Post,
        path: "/12/accounts/{account_id}/line_items",
        category: ToolCategory::Ads,
        profiles: ADMIN_ONLY,
        scopes: &["ads.read", "ads.write"],
        params: &[
            PARAM_ACCOUNT_ID,
            PARAM_CAMPAIGN_ID,
            ParamDef {
                name: "bid_amount_local_micro",
                param_type: ParamType::Integer,
                required: true,
                description: "Bid amount in microcurrency units",
                default: None,
            },
            ParamDef {
                name: "product_type",
                param_type: ParamType::String,
                required: true,
                description: "Product type: PROMOTED_TWEETS, PROMOTED_ACCOUNT",
                default: None,
            },
            ParamDef {
                name: "placements",
                param_type: ParamType::StringArray,
                required: true,
                description: "Comma-separated placements: ALL_ON_TWITTER, PUBLISHER_NETWORK",
                default: None,
            },
            ParamDef {
                name: "objective",
                param_type: ParamType::String,
                required: true,
                description: "Campaign objective: AWARENESS, ENGAGEMENTS, VIDEO_VIEWS, etc.",
                default: None,
            },
            ParamDef {
                name: "bid_type",
                param_type: ParamType::String,
                required: false,
                description: "Bid type: AUTO, MAX, TARGET",
                default: None,
            },
            ParamDef {
                name: "total_budget_amount_local_micro",
                param_type: ParamType::Integer,
                required: false,
                description: "Total line item budget in microcurrency units",
                default: None,
            },
        ],
        error_codes: X_WRITE_ERR,
        api_version: "ads-v12",
        group: "ads",
        host: Some("ads-api.x.com"),
    },
    EndpointDef {
        tool_name: "x_ads_line_items",
        description: "List line items (ad groups) for an advertising account",
        method: HttpMethod::Get,
        path: "/12/accounts/{account_id}/line_items",
        category: ToolCategory::Ads,
        profiles: ADMIN_ONLY,
        scopes: &["ads.read"],
        params: &[
            PARAM_ACCOUNT_ID,
            ParamDef {
                name: "campaign_ids",
                param_type: ParamType::StringArray,
                required: false,
                description: "Comma-separated campaign IDs to filter by",
                default: None,
            },
            ParamDef {
                name: "line_item_ids",
                param_type: ParamType::StringArray,
                required: false,
                description: "Comma-separated line item IDs to filter by",
                default: None,
            },
            PARAM_WITH_DELETED,
            PARAM_ADS_CURSOR,
            PARAM_ADS_COUNT,
        ],
        error_codes: X_READ_ERR,
        api_version: "ads-v12",
        group: "ads",
        host: Some("ads-api.x.com"),
    },
    EndpointDef {
        tool_name: "x_ads_promoted_tweet_create",
        description: "Promote a tweet under a line item",
        method: HttpMethod::Post,
        path: "/12/accounts/{account_id}/promoted_tweets",
        category: ToolCategory::Ads,
        profiles: ADMIN_ONLY,
        scopes: &["ads.read", "ads.write"],
        params: &[
            PARAM_ACCOUNT_ID,
            ParamDef {
                name: "line_item_id",
                param_type: ParamType::String,
                required: true,
                description: "Line item ID to associate the promoted tweet with",
                default: None,
            },
            ParamDef {
                name: "tweet_ids",
                param_type: ParamType::StringArray,
                required: true,
                description: "Comma-separated tweet IDs to promote",
                default: None,
            },
        ],
        error_codes: X_WRITE_ERR,
        api_version: "ads-v12",
        group: "ads",
        host: Some("ads-api.x.com"),
    },
    EndpointDef {
        tool_name: "x_ads_promoted_tweets",
        description: "List promoted tweets for an advertising account",
        method: HttpMethod::Get,
        path: "/12/accounts/{account_id}/promoted_tweets",
        category: ToolCategory::Ads,
        profiles: ADMIN_ONLY,
        scopes: &["ads.read"],
        params: &[
            PARAM_ACCOUNT_ID,
            ParamDef {
                name: "line_item_ids",
                param_type: ParamType::StringArray,
                required: false,
                description: "Comma-separated line item IDs to filter by",
                default: None,
            },
            PARAM_WITH_DELETED,
            PARAM_ADS_CURSOR,
            PARAM_ADS_COUNT,
        ],
        error_codes: X_READ_ERR,
        api_version: "ads-v12",
        group: "ads",
        host: Some("ads-api.x.com"),
    },
    EndpointDef {
        tool_name: "x_ads_targeting_create",
        description: "Create targeting criteria for a line item",
        method: HttpMethod::Post,
        path: "/12/accounts/{account_id}/targeting_criteria",
        category: ToolCategory::Ads,
        profiles: ADMIN_ONLY,
        scopes: &["ads.read", "ads.write"],
        params: &[
            PARAM_ACCOUNT_ID,
            ParamDef {
                name: "line_item_id",
                param_type: ParamType::String,
                required: true,
                description: "Line item ID to apply targeting to",
                default: None,
            },
            ParamDef {
                name: "targeting_type",
                param_type: ParamType::String,
                required: true,
                description: "Targeting type: LOCATION, KEYWORD, INTEREST, etc.",
                default: None,
            },
            ParamDef {
                name: "targeting_value",
                param_type: ParamType::String,
                required: true,
                description: "Targeting value (depends on targeting_type)",
                default: None,
            },
        ],
        error_codes: X_WRITE_ERR,
        api_version: "ads-v12",
        group: "ads",
        host: Some("ads-api.x.com"),
    },
    EndpointDef {
        tool_name: "x_ads_targeting_criteria",
        description: "List targeting criteria for an advertising account",
        method: HttpMethod::Get,
        path: "/12/accounts/{account_id}/targeting_criteria",
        category: ToolCategory::Ads,
        profiles: ADMIN_ONLY,
        scopes: &["ads.read"],
        params: &[
            PARAM_ACCOUNT_ID,
            ParamDef {
                name: "line_item_ids",
                param_type: ParamType::StringArray,
                required: false,
                description: "Comma-separated line item IDs to filter by",
                default: None,
            },
            PARAM_WITH_DELETED,
            PARAM_ADS_CURSOR,
            PARAM_ADS_COUNT,
        ],
        error_codes: X_READ_ERR,
        api_version: "ads-v12",
        group: "ads",
        host: Some("ads-api.x.com"),
    },
    EndpointDef {
        tool_name: "x_ads_targeting_delete",
        description: "Delete targeting criteria from a line item",
        method: HttpMethod::Delete,
        path: "/12/accounts/{account_id}/targeting_criteria/{id}",
        category: ToolCategory::Ads,
        profiles: ADMIN_ONLY,
        scopes: &["ads.read", "ads.write"],
        params: &[PARAM_ACCOUNT_ID, PARAM_ID],
        error_codes: X_WRITE_ERR,
        api_version: "ads-v12",
        group: "ads",
        host: Some("ads-api.x.com"),
    },
    // ── Compliance (4) ────────────────────────────────────────────────
    EndpointDef {
        tool_name: "x_v2_compliance_jobs",
        description: "List compliance jobs for GDPR and data deletion tracking",
        method: HttpMethod::Get,
        path: "/2/compliance/jobs",
        category: ToolCategory::Compliance,
        profiles: ADMIN_ONLY,
        scopes: &["compliance.write"],
        params: &[PARAM_COMPLIANCE_TYPE, PARAM_COMPLIANCE_STATUS],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "compliance",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_compliance_job_by_id",
        description: "Get a single compliance job by ID",
        method: HttpMethod::Get,
        path: "/2/compliance/jobs/{id}",
        category: ToolCategory::Compliance,
        profiles: ADMIN_ONLY,
        scopes: &["compliance.write"],
        params: &[PARAM_ID],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "compliance",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_compliance_job_create",
        description: "Create a new compliance job for batch user or tweet lookups",
        method: HttpMethod::Post,
        path: "/2/compliance/jobs",
        category: ToolCategory::Compliance,
        profiles: ADMIN_ONLY,
        scopes: &["compliance.write"],
        params: &[
            PARAM_COMPLIANCE_TYPE,
            ParamDef {
                name: "name",
                param_type: ParamType::String,
                required: false,
                description: "Optional human-readable name for the compliance job",
                default: None,
            },
            ParamDef {
                name: "resumable",
                param_type: ParamType::Boolean,
                required: false,
                description: "Whether the job should be resumable (default: false)",
                default: Some("false"),
            },
        ],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "compliance",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_usage_tweets",
        description: "Get tweet usage data for the authenticated app (cap consumption)",
        method: HttpMethod::Get,
        path: "/2/usage/tweets",
        category: ToolCategory::Compliance,
        profiles: ADMIN_ONLY,
        scopes: &["usage.read"],
        params: &[PARAM_USAGE_DAYS],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "compliance",
        host: None,
    },
    // ── Stream Rules (3) ──────────────────────────────────────────────
    EndpointDef {
        tool_name: "x_v2_stream_rules_list",
        description: "List active filtered stream rules",
        method: HttpMethod::Get,
        path: "/2/tweets/search/stream/rules",
        category: ToolCategory::Compliance,
        profiles: ADMIN_ONLY,
        scopes: &["tweet.read"],
        params: &[],
        error_codes: X_READ_ERR,
        api_version: "v2",
        group: "compliance",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_stream_rules_add",
        description: "Add rules to the filtered stream (max 25 rules per request)",
        method: HttpMethod::Post,
        path: "/2/tweets/search/stream/rules",
        category: ToolCategory::Compliance,
        profiles: ADMIN_ONLY,
        scopes: &["tweet.read"],
        params: &[PARAM_STREAM_RULE_VALUE, PARAM_STREAM_RULE_TAG],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "compliance",
        host: None,
    },
    EndpointDef {
        tool_name: "x_v2_stream_rules_delete",
        description: "Delete rules from the filtered stream by rule IDs",
        method: HttpMethod::Post,
        path: "/2/tweets/search/stream/rules",
        category: ToolCategory::Compliance,
        profiles: ADMIN_ONLY,
        scopes: &["tweet.read"],
        params: &[PARAM_STREAM_RULE_IDS],
        error_codes: X_WRITE_ERR,
        api_version: "v2",
        group: "compliance",
        host: None,
    },
];
