"""Tool registry adapter for Gremlin Autopilot.

Adapts the existing tool registry from gremlin_tool_registry.py to add
autopilot-specific metadata and filtering based on available credentials.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Callable, TYPE_CHECKING

import copy

if TYPE_CHECKING:
    from .contracts import PlanStep

# Default risk category mapping (fail-closed).
RISK_CATEGORY_BY_LEVEL = {
    0: "read_only",
    1: "reversible_write",
    2: "bulk_write",
    3: "irreversible",
}

READ_ONLY_META = {
    "risk_level": 0,
    "risk_category": "read_only",
    "impact_tier": 1,
    "idempotent": True,
    "blast_radius": "single_record",
}

REVERSIBLE_WRITE_META = {
    "risk_level": 1,
    "risk_category": "reversible_write",
    "impact_tier": 2,
    "idempotent": True,
    "blast_radius": "bulk_records",
}

BULK_WRITE_META = {
    "risk_level": 2,
    "risk_category": "bulk_write",
    "impact_tier": 3,
    "idempotent": False,
    "blast_radius": "bulk_records",
}

IRREVERSIBLE_META = {
    "risk_level": 3,
    "risk_category": "irreversible",
    "impact_tier": 4,
    "idempotent": False,
    "blast_radius": "external_side_effect",
}

# Tools that write to external systems (non-rollbackable)
EXTERNAL_WRITE_TOOLS = {
    "sfdc_push",
    "sfdc_create_lead",
    "sfdc_update_account",
    "hubspot_create",
    "hubspot_update",
    "sequencer_push",
    "sequencer_enroll",
    "justcall_send",
    "apollo_push",
    "instantly_add",
    "smartlead_add",
}

# Tools that require specific credentials
CREDENTIAL_REQUIREMENTS = {
    "match_salesforce_account": ["salesforce"],
    "resolve_company": ["salesforce"],  # or foundrygraph
    "sfdc_push": ["salesforce"],
    "sfdc_create_lead": ["salesforce"],
    "sfdc_update_account": ["salesforce"],
    "hubspot_create": ["hubspot"],
    "hubspot_update": ["hubspot"],
    "hubspot_pull": ["hubspot"],
    "hubspot_associate": ["hubspot"],
    "sequence.pause": ["salesforce", "outreach"],
    "sequencer_push": ["instantly", "smartlead", "apollo"],
    "apollo_push": ["apollo"],
    "instantly_add": ["instantly"],
    "smartlead_add": ["smartlead"],
    "justcall_send": ["justcall"],
    "enrich": ["pdl", "apollo", "clearbit"],
    "fg_parent": ["foundrygraph"],
    "fg_enrich": ["foundrygraph"],
}

# Tools with approximate previews (not fully deterministic)
UNTRUSTED_PREVIEW_TOOLS = {
    "enrich",  # External API results may vary
    "resolve_company",  # Resolution depends on external data
    "match_salesforce_account",  # Match results depend on SFDC state
    "dedupe",  # Dedup groups depend on algorithm state
}


@dataclass
class AutopilotToolDefinition:
    """Extended tool definition with autopilot-specific metadata."""

    name: str
    category: str
    description: str
    parameters: dict[str, Any]
    cli_equivalent: str | None = None
    # Autonomy metadata (policy-gated fields)
    risk_level: int = 3
    risk_category: str | None = None
    impact_tier: int = 4  # legacy informational only
    idempotent: bool = False
    rollback_supported: bool = True
    rollback_method: str | None = None
    requires_human_auth: bool = False
    blast_radius: str | None = None
    policy_tags: list[str] = field(default_factory=list)
    default_prechecks: list[str] = field(default_factory=list)
    default_postchecks: list[str] = field(default_factory=list)
    # Backwards-compatible fields for existing UI/agent flows
    destructive: bool = False
    preview_trustworthy: bool = True
    writes_external: bool = False
    requires_credentials: list[str] = field(default_factory=list)

    def __post_init__(self) -> None:
        try:
            level = int(self.risk_level)
        except Exception:
            level = 3
        if level < 0:
            level = 0
        if level > 3:
            level = 3
        self.risk_level = level
        if not self.risk_category:
            self.risk_category = RISK_CATEGORY_BY_LEVEL.get(level, "irreversible")
        if not self.blast_radius:
            if self.risk_category == "read_only":
                self.blast_radius = "single_record"
            elif self.risk_category in ("reversible_write", "bulk_write"):
                self.blast_radius = "bulk_records"
            elif self.risk_category == "metadata_write":
                self.blast_radius = "metadata"
            else:
                self.blast_radius = "external_side_effect"

    def to_llm_schema(self, available_credentials: set[str] | None = None) -> dict[str, Any]:
        """Convert to LLM tool schema format."""
        params = copy.deepcopy(self.parameters)

        if available_credentials:
            if self.name == "sequencer_push":
                provider_param = params.get("provider", {})
                if "enum" in provider_param:
                    provider_param["enum"] = [
                        provider
                        for provider in provider_param["enum"]
                        if provider in available_credentials
                    ]
            elif self.name == "resolve_company":
                target_param = params.get("target", {})
                if "enum" in target_param:
                    allowed_targets: list[str] = []
                    if "salesforce" in available_credentials:
                        allowed_targets.append("salesforce")
                    if "foundrygraph" in available_credentials:
                        allowed_targets.append("foundrygraph")
                    if "smart" in target_param["enum"]:
                        allowed_targets.append("smart")
                    target_param["enum"] = allowed_targets

        return {
            "name": self.name,
            "description": self.description,
            "parameters": {
                "type": "object",
                "properties": params,
                "required": list(params.keys()),
            },
        }

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary for API responses."""
        return {
            "name": self.name,
            "category": self.category,
            "description": self.description,
            "parameters": self.parameters,
            "cli_equivalent": self.cli_equivalent,
            "risk_level": self.risk_level,
            "risk_category": self.risk_category,
            "impact_tier": self.impact_tier,
            "idempotent": self.idempotent,
            "rollback_supported": self.rollback_supported,
            "rollback_method": self.rollback_method,
            "requires_human_auth": self.requires_human_auth,
            "blast_radius": self.blast_radius,
            "policy_tags": list(self.policy_tags),
            "default_prechecks": list(self.default_prechecks),
            "default_postchecks": list(self.default_postchecks),
            "destructive": self.destructive,
            "preview_trustworthy": self.preview_trustworthy,
            "writes_external": self.writes_external,
            "requires_credentials": self.requires_credentials,
        }


# Tool handler signature for execution dispatch.
ToolHandler = Callable[["PlanStep", AutopilotToolDefinition | None], dict[str, Any]]


# Define transform tools with autopilot metadata
TRANSFORM_TOOLS: list[AutopilotToolDefinition] = [
    AutopilotToolDefinition(
        name="normalize_company",
        category="transform",
        description="Standardize company names by removing Inc, LLC, etc.",
        parameters={"column": {"type": "string", "description": "Column name to normalize"}},
        cli_equivalent="g-gremlin transform --normalize-company {column}",
        destructive=False,
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="clean_website",
        category="transform",
        description="Normalize websites to a consistent host/path string without scheme, query, or fragment.",
        parameters={"column": {"type": "string", "description": "Website or URL column"}},
        cli_equivalent="g-gremlin transform --clean-website {column}",
        destructive=False,
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="company_to_domain",
        category="transform",
        description="Resolve company names to domains with confidence scores.",
        parameters={
            "column": {"type": "string", "description": "Company column"},
            "output_column": {"type": "string", "description": "Output column name", "default": "Domain"},
        },
        cli_equivalent="g-gremlin transform --company-to-domain {column}",
        destructive=False,
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="is_business_email",
        category="transform",
        description="Flag business vs personal email addresses.",
        parameters={
            "column": {"type": "string", "description": "Email column"},
            "output_column": {"type": "string", "description": "Output column name", "default": "Is Business"},
        },
        cli_equivalent="g-gremlin transform --is-business-email {column}",
        destructive=False,
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="extract_domain_from_email",
        category="transform",
        description="Extract domains from email addresses.",
        parameters={
            "column": {"type": "string", "description": "Email column"},
            "output_column": {"type": "string", "description": "Output column name", "default": "Domain"},
        },
        cli_equivalent="g-gremlin transform --extract-domain {column}",
        destructive=False,
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="fix_phone_format",
        category="transform",
        description="Format phone numbers to international E.164 format.",
        parameters={
            "column": {"type": "string", "description": "Phone column"},
            "country": {"type": "string", "description": "Default country code", "default": "US"},
        },
        cli_equivalent="g-gremlin transform --fix-phone {column}",
        destructive=False,
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="normalize_country",
        category="transform",
        description="Normalize country names to canonical values.",
        parameters={"column": {"type": "string", "description": "Country column"}},
        cli_equivalent="g-gremlin transform --normalize-country {column}",
        destructive=False,
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="normalize_state",
        category="transform",
        description="Standardize state or province values.",
        parameters={
            "column": {"type": "string", "description": "State/province column"},
            "country": {"type": "string", "description": "Country for context", "default": "US"},
        },
        cli_equivalent="g-gremlin transform --normalize-state {column}",
        destructive=False,
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="normalize_title",
        category="transform",
        description="Standardize job titles into best-effort title/department/seniority. Blank or unrecognized titles default seniority to IC.",
        parameters={"column": {"type": "string", "description": "Title column"}},
        cli_equivalent="g-gremlin transform --normalize-title {column}",
        destructive=False,
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="split_fullname",
        category="transform",
        description="Split full names into first and last name columns.",
        parameters={"column": {"type": "string", "description": "Full name column"}},
        cli_equivalent="g-gremlin transform --split-fullname {column}",
        destructive=False,
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="clean_name",
        category="transform",
        description="Normalize personal names with proper casing.",
        parameters={"column": {"type": "string", "description": "Name column"}},
        cli_equivalent="g-gremlin transform --clean-name {column}",
        destructive=False,
        **READ_ONLY_META,
    ),
]

# Define match tools
MATCH_TOOLS: list[AutopilotToolDefinition] = [
    AutopilotToolDefinition(
        name="dedupe",
        category="match",
        description="Find and resolve duplicate rows based on specified columns.",
        parameters={
            "key_columns": {"type": "array", "items": {"type": "string"}, "description": "Columns to compare"},
            "threshold": {"type": "number", "description": "Similarity threshold 0-1", "default": 0.85},
        },
        cli_equivalent="g-gremlin dedup plan --key-columns {key_columns} --threshold {threshold}",
        destructive=True,
        preview_trustworthy=False,  # Dedup groups may vary
        **REVERSIBLE_WRITE_META,
    ),
    AutopilotToolDefinition(
        name="match_salesforce_account",
        category="match",
        description="Match companies against Salesforce Accounts.",
        parameters={
            "column": {"type": "string", "description": "Column with company names"},
            "threshold": {"type": "number", "description": "Match threshold 0-100", "default": 80},
        },
        cli_equivalent="g-gremlin sfdc match --column {column} --threshold {threshold}",
        destructive=False,
        preview_trustworthy=False,
        requires_credentials=["salesforce"],
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="resolve_company",
        category="match",
        description="Resolve company names using Salesforce or FoundryGraph.",
        parameters={
            "column": {"type": "string", "description": "Column with company names"},
            "target": {"type": "string", "enum": ["salesforce", "foundrygraph", "smart"], "default": "smart"},
        },
        cli_equivalent="g-gremlin fg resolve --column {column} --target {target}",
        destructive=False,
        preview_trustworthy=False,
        requires_credentials=["salesforce", "foundrygraph"],
        **READ_ONLY_META,
    ),
]

# Scout scan tools (read-only)
SCOUT_TOOLS: list[AutopilotToolDefinition] = [
    AutopilotToolDefinition(
        name="scout.user_provisioning_parity",
        category="scout",
        description="Scout scan for Salesforce user provisioning parity.",
        parameters={},
        requires_credentials=["salesforce"],
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="scout.forecast_hierarchy_drift",
        category="scout",
        description="Scout scan for Salesforce forecasting hierarchy drift.",
        parameters={},
        requires_credentials=["salesforce"],
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="scout.automation_failure_impact",
        category="scout",
        description="Scout scan for automation failure impact.",
        parameters={},
        requires_credentials=["salesforce"],
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="scout.lead_to_account_match_health",
        category="scout",
        description="Scout scan for lead-to-account match health.",
        parameters={},
        requires_credentials=["salesforce"],
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="scout.integration_health",
        category="scout",
        description="Scout scan for integration health monitor.",
        parameters={},
        requires_credentials=["salesforce"],
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="scout.workflow_impact",
        category="scout",
        description="Scout scan for workflow impact analysis.",
        parameters={},
        requires_credentials=["salesforce"],
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="scout.license_utilization",
        category="scout",
        description="Scout scan for license utilization.",
        parameters={},
        requires_credentials=["salesforce"],
        **READ_ONLY_META,
    ),
]

# Autopilot admin actions (Salesforce v1)
AUTOPILOT_ADMIN_TOOLS: list[AutopilotToolDefinition] = [
    AutopilotToolDefinition(
        name="sfdc.record.create",
        category="sfdc_admin",
        description="Create a Salesforce record.",
        parameters={
            "sobject": {"type": "string", "description": "Salesforce object API name"},
            "values": {"type": "object", "description": "Field values for the new record"},
            "org_alias": {"type": "string", "description": "Target org alias", "default": ""},
        },
        destructive=False,
        rollback_supported=True,
        rollback_method="delete",
        requires_credentials=["salesforce"],
        policy_tags=["reversible_write"],
        writes_external=False,
        **{**REVERSIBLE_WRITE_META, "idempotent": False, "blast_radius": "single_record"},
    ),
    AutopilotToolDefinition(
        name="sfdc.record.update",
        category="sfdc_admin",
        description="Update fields on a Salesforce record.",
        parameters={
            "sobject": {"type": "string", "description": "Salesforce object API name"},
            "record_id": {"type": "string", "description": "Record ID"},
            "fields": {"type": "object", "description": "Field updates"},
            "org_alias": {"type": "string", "description": "Target org alias", "default": ""},
        },
        destructive=False,
        rollback_supported=True,
        rollback_method="snapshot",
        requires_credentials=["salesforce"],
        policy_tags=["reversible_write"],
        default_prechecks=["sfdc.record.exists"],
        default_postchecks=["sfdc.record.updated"],
        writes_external=False,
        **{**REVERSIBLE_WRITE_META, "idempotent": True, "blast_radius": "single_record"},
    ),
    AutopilotToolDefinition(
        name="sfdc.record.delete",
        category="sfdc_admin",
        description="Delete a Salesforce record.",
        parameters={
            "sobject": {"type": "string", "description": "Salesforce object API name"},
            "record_id": {"type": "string", "description": "Record ID"},
            "org_alias": {"type": "string", "description": "Target org alias", "default": ""},
        },
        destructive=True,
        rollback_supported=False,
        requires_credentials=["salesforce"],
        policy_tags=["record.delete", "destructive_write"],
        default_prechecks=["sfdc.record.exists"],
        writes_external=False,
        **{**REVERSIBLE_WRITE_META, "idempotent": True, "blast_radius": "single_record", "risk_level": 2},
    ),
    AutopilotToolDefinition(
        name="sfdc.record.enrich_missing_fields",
        category="sfdc_admin",
        description="Fill blank Salesforce firmographic fields from configured enrichment providers.",
        parameters={
            "sobject": {"type": "string", "description": "Salesforce object API name", "default": "Account"},
            "records": {"type": "array", "description": "Evidence records with missing_fields metadata"},
            "record_ids": {"type": "array", "items": {"type": "string"}, "description": "Target record IDs"},
            "target_fields": {
                "type": "array",
                "items": {"type": "string"},
                "description": "Salesforce fields to enrich",
                "default": ["Website", "Industry", "NumberOfEmployees"],
            },
            "providers": {
                "type": "array",
                "items": {"type": "string"},
                "description": "Provider precedence order",
                "default": ["zoominfo", "apollo", "clearbit"],
            },
            "confidence_floor": {
                "type": "number",
                "description": "Minimum confidence required to write values",
                "default": 0.7,
            },
            "max_provider_calls_per_run": {
                "type": "number",
                "description": "Cap provider API attempts per step",
                "default": 100,
            },
            "only_fill_empty_fields": {
                "type": "boolean",
                "description": "Only fill null/blank fields",
                "default": True,
            },
            "org_alias": {"type": "string", "description": "Target org alias", "default": ""},
        },
        destructive=False,
        rollback_supported=True,
        rollback_method="snapshot",
        requires_credentials=["zoominfo", "apollo", "clearbit"],
        policy_tags=["record.enrich", "reversible_write"],
        default_prechecks=["sfdc.record.exists"],
        default_postchecks=["sfdc.record.updated"],
        writes_external=False,
        **{**BULK_WRITE_META, "idempotent": True, "risk_level": 1},
    ),
    AutopilotToolDefinition(
        name="sfdc.user.assign_permission_sets",
        category="sfdc_admin",
        description="Assign permission sets to Salesforce users.",
        parameters={
            "user_ids": {"type": "array", "items": {"type": "string"}, "description": "Salesforce User IDs"},
            "permission_set_names": {
                "type": "array",
                "items": {"type": "string"},
                "description": "Permission set API names",
            },
        },
        destructive=False,
        rollback_supported=True,
        rollback_method="compensating",
        requires_credentials=["salesforce"],
        policy_tags=["user_admin"],
        default_prechecks=["sfdc.user.exists", "sfdc.user.not_already_assigned"],
        default_postchecks=["sfdc.user.assignment_verified"],
        **REVERSIBLE_WRITE_META,
    ),
    AutopilotToolDefinition(
        name="sfdc.user.assign_permission_set_groups",
        category="sfdc_admin",
        description="Assign permission set groups to Salesforce users.",
        parameters={
            "user_ids": {"type": "array", "items": {"type": "string"}, "description": "Salesforce User IDs"},
            "permission_set_group_names": {
                "type": "array",
                "items": {"type": "string"},
                "description": "Permission set group API names",
            },
        },
        destructive=False,
        rollback_supported=True,
        rollback_method="compensating",
        requires_credentials=["salesforce"],
        policy_tags=["user_admin"],
        default_prechecks=["sfdc.user.exists", "sfdc.user.not_already_assigned"],
        default_postchecks=["sfdc.user.assignment_verified"],
        **REVERSIBLE_WRITE_META,
    ),
    AutopilotToolDefinition(
        name="sfdc.user.add_to_queue_group",
        category="sfdc_admin",
        description="Add Salesforce users to queues or public groups.",
        parameters={
            "user_ids": {"type": "array", "items": {"type": "string"}, "description": "Salesforce User IDs"},
            "group_names": {
                "type": "array",
                "items": {"type": "string"},
                "description": "Queue or group API names",
            },
        },
        destructive=False,
        rollback_supported=True,
        rollback_method="compensating",
        requires_credentials=["salesforce"],
        policy_tags=["user_admin"],
        default_prechecks=["sfdc.user.exists", "sfdc.group.exists"],
        default_postchecks=["sfdc.group.membership_verified"],
        **REVERSIBLE_WRITE_META,
    ),
    AutopilotToolDefinition(
        name="sfdc.user.deactivate",
        category="sfdc_admin",
        description="Deactivate Salesforce users to reclaim licenses.",
        parameters={
            "user_ids": {"type": "array", "items": {"type": "string"}, "description": "Salesforce User IDs"},
            "org_alias": {"type": "string", "description": "Target org alias", "default": ""},
        },
        destructive=False,
        rollback_supported=True,
        rollback_method="compensating",
        requires_credentials=["salesforce"],
        policy_tags=["license_management", "user_admin"],
        default_prechecks=["sfdc.user.exists", "sfdc.user.not_system_admin"],
        default_postchecks=["sfdc.user.deactivated"],
        writes_external=False,
        **BULK_WRITE_META,
    ),
    AutopilotToolDefinition(
        name="sfdc.record.reassign_owner",
        category="sfdc_admin",
        description="Bulk reassign record ownership to a user or queue.",
        parameters={
            "sobject": {"type": "string", "description": "Salesforce object API name"},
            "record_ids": {"type": "array", "items": {"type": "string"}, "description": "Record IDs"},
            "new_owner_id": {"type": "string", "description": "New owner User or Queue ID"},
            "org_alias": {"type": "string", "description": "Target org alias", "default": ""},
        },
        destructive=False,
        rollback_supported=True,
        rollback_method="snapshot",
        requires_credentials=["salesforce"],
        policy_tags=["ownership_management", "user_admin"],
        default_prechecks=["sfdc.record.exists", "sfdc.owner.exists_and_active"],
        default_postchecks=["sfdc.record.owner_updated"],
        writes_external=False,
        **{**BULK_WRITE_META, "idempotent": True},
    ),
    AutopilotToolDefinition(
        name="sfdc.forecast.assign_user_to_role",
        category="sfdc_admin",
        description="Assign or move Salesforce users within the forecasting hierarchy.",
        parameters={
            "user_id": {"type": "string", "description": "Salesforce User ID"},
            "role_id": {"type": "string", "description": "Salesforce Role ID"},
        },
        destructive=False,
        rollback_supported=True,
        rollback_method="compensating",
        requires_credentials=["salesforce"],
        policy_tags=["forecasting"],
        default_prechecks=["sfdc.user.exists", "sfdc.role.exists"],
        default_postchecks=["sfdc.forecast.hierarchy_verified"],
        **REVERSIBLE_WRITE_META,
    ),
    AutopilotToolDefinition(
        name="tasks.create",
        category="tasks",
        description="Create a Salesforce task (manual follow-up or auth task).",
        parameters={
            "owner_id": {"type": "string", "description": "Salesforce User ID"},
            "subject": {"type": "string", "description": "Task subject"},
            "description": {"type": "string", "description": "Task description"},
            "due_date": {"type": "string", "description": "Due date (YYYY-MM-DD)", "default": ""},
        },
        destructive=False,
        rollback_supported=True,
        rollback_method="delete",
        requires_credentials=["salesforce"],
        policy_tags=["user_admin", "external_side_effects"],
        default_prechecks=["sfdc.user.exists"],
        default_postchecks=["tasks.created"],
        writes_external=False,
        **REVERSIBLE_WRITE_META,
    ),
    AutopilotToolDefinition(
        name="sfdc.followup.enforce",
        category="sfdc_admin",
        description="Enforce post-meeting follow-up with task creation and optional stage hold + Slack nudge.",
        parameters={
            "records": {"type": "array", "description": "Evidence records from meeting follow-up scout"},
            "record_ids": {"type": "array", "items": {"type": "string"}, "description": "Meeting Event IDs"},
            "owner_id": {"type": "string", "description": "Task owner override", "default": ""},
            "subject": {"type": "string", "description": "Task subject", "default": "Autopilot follow-up"},
            "description": {"type": "string", "description": "Task description", "default": ""},
            "due_date": {"type": "string", "description": "Task due date (YYYY-MM-DD)", "default": ""},
            "apply_stage_hold": {"type": "boolean", "description": "Set related opportunity stage hold", "default": False},
            "hold_stage_name": {"type": "string", "description": "Opportunity hold stage value", "default": "Follow-up Required"},
            "notify_slack": {"type": "boolean", "description": "Send Slack nudge", "default": False},
            "slack_channel": {"type": "string", "description": "Slack channel override", "default": ""},
            "slack_severity": {"type": "string", "description": "Slack severity", "default": "high"},
            "org_alias": {"type": "string", "description": "Target org alias", "default": ""},
        },
        destructive=False,
        rollback_supported=True,
        rollback_method="delete",
        requires_credentials=["salesforce"],
        policy_tags=["task.create", "opportunity.stage", "notification.slack"],
        default_prechecks=["sfdc.record.exists"],
        default_postchecks=["tasks.created"],
        writes_external=False,
        **{**BULK_WRITE_META, "idempotent": True, "risk_level": 1},
    ),
    AutopilotToolDefinition(
        name="sequence.pause",
        category="compliance",
        description="Pause active sequence enrollments and tag source CRM records.",
        parameters={
            "record_ids": {"type": "array", "items": {"type": "string"}, "description": "Target CRM record IDs"},
            "records": {"type": "array", "description": "Evidence records with sequence context"},
            "reason_code": {"type": "string", "description": "Pause reason code", "default": "DNC_IN_ACTIVE_SEQUENCE"},
            "tag_prefix": {"type": "string", "description": "Tag prefix for CRM markers", "default": "gremlin:paused"},
            "tag_field": {"type": "string", "description": "CRM field used to store pause tag", "default": "Gremlin_Pause_Tag__c"},
            "blast_radius_max_records_per_run": {"type": "number", "description": "Max records to process in this step", "default": 50},
        },
        destructive=False,
        rollback_supported=True,
        rollback_method="compensating",
        requires_credentials=["salesforce", "outreach"],
        policy_tags=["sequence.pause", "compliance"],
        default_postchecks=["sequence.pause.applied"],
        writes_external=False,
        **{**REVERSIBLE_WRITE_META, "blast_radius": "bulk_records"},
    ),
    AutopilotToolDefinition(
        name="slack.notify",
        category="notifications",
        description="Send a Slack alert to a channel.",
        parameters={
            "channel": {"type": "string", "description": "Slack channel (e.g., #revops-alerts)"},
            "message": {"type": "string", "description": "Alert message text"},
            "severity": {"type": "string", "description": "Severity label", "default": "info"},
            "title": {"type": "string", "description": "Optional alert title", "default": ""},
        },
        destructive=False,
        rollback_supported=False,
        requires_credentials=[],
        policy_tags=["external_notify"],
        writes_external=False,
        risk_level=1,
        risk_category="reversible_write",
        impact_tier=2,
        idempotent=False,
        blast_radius="external_side_effect",
    ),
]

ABSTRACT_ACTION_TOOLS: list[AutopilotToolDefinition] = [
    AutopilotToolDefinition(
        name="user.offboard",
        category="sfdc_admin",
        description="Abstract offboarding action that delegates to user deactivation or owner reassignment.",
        parameters={
            "record_ids": {"type": "array", "items": {"type": "string"}, "description": "Target IDs"},
            "offboard_action": {
                "type": "string",
                "description": "Delegated offboarding mode",
                "default": "deactivate",
            },
            "sobject": {"type": "string", "description": "Salesforce object API name", "default": ""},
            "new_owner_id": {"type": "string", "description": "Replacement owner ID", "default": ""},
            "org_alias": {"type": "string", "description": "Target org alias", "default": ""},
        },
        destructive=False,
        rollback_supported=True,
        rollback_method="compensating",
        requires_credentials=["salesforce"],
        policy_tags=["ownership_management", "user_admin"],
        writes_external=False,
        **{**BULK_WRITE_META, "idempotent": True},
    ),
    AutopilotToolDefinition(
        name="record.enrich",
        category="sfdc_admin",
        description="Abstract enrichment action that delegates to the Salesforce missing-fields enricher.",
        parameters={
            "records": {"type": "array", "description": "Evidence records with missing_fields metadata"},
            "record_ids": {"type": "array", "items": {"type": "string"}, "description": "Target record IDs"},
            "target_fields": {
                "type": "array",
                "items": {"type": "string"},
                "description": "Salesforce fields to enrich",
                "default": ["Website", "Industry", "NumberOfEmployees"],
            },
            "providers": {
                "type": "array",
                "items": {"type": "string"},
                "description": "Provider precedence order",
                "default": ["zoominfo", "apollo", "clearbit"],
            },
            "confidence_floor": {
                "type": "number",
                "description": "Minimum confidence required to write values",
                "default": 0.7,
            },
            "org_alias": {"type": "string", "description": "Target org alias", "default": ""},
        },
        destructive=False,
        rollback_supported=True,
        rollback_method="snapshot",
        requires_credentials=["zoominfo", "apollo", "clearbit"],
        policy_tags=["record.enrich", "reversible_write"],
        default_prechecks=["sfdc.record.exists"],
        default_postchecks=["sfdc.record.updated"],
        writes_external=False,
        **{**BULK_WRITE_META, "idempotent": True, "risk_level": 1},
    ),
    AutopilotToolDefinition(
        name="meeting.followup.enforce",
        category="sfdc_admin",
        description="Abstract meeting follow-up enforcement action that delegates to the Salesforce handler.",
        parameters={
            "records": {"type": "array", "description": "Evidence records from meeting follow-up scout"},
            "record_ids": {"type": "array", "items": {"type": "string"}, "description": "Meeting Event IDs"},
            "owner_id": {"type": "string", "description": "Task owner override", "default": ""},
            "subject": {"type": "string", "description": "Task subject", "default": "Autopilot follow-up"},
            "description": {"type": "string", "description": "Task description", "default": ""},
            "due_date": {"type": "string", "description": "Task due date (YYYY-MM-DD)", "default": ""},
            "apply_stage_hold": {
                "type": "boolean",
                "description": "Set related opportunity stage hold",
                "default": False,
            },
            "hold_stage_name": {
                "type": "string",
                "description": "Opportunity hold stage value",
                "default": "Follow-up Required",
            },
            "notify_slack": {"type": "boolean", "description": "Send Slack nudge", "default": False},
            "slack_channel": {"type": "string", "description": "Slack channel override", "default": ""},
            "slack_severity": {"type": "string", "description": "Slack severity", "default": "high"},
            "org_alias": {"type": "string", "description": "Target org alias", "default": ""},
        },
        destructive=False,
        rollback_supported=True,
        rollback_method="delete",
        requires_credentials=["salesforce"],
        policy_tags=["task.create", "opportunity.stage", "notification.slack"],
        default_prechecks=["sfdc.record.exists"],
        default_postchecks=["tasks.created"],
        writes_external=False,
        **{**BULK_WRITE_META, "idempotent": True, "risk_level": 1},
    ),
    AutopilotToolDefinition(
        name="notification.slack",
        category="notifications",
        description="Abstract Slack routing action that delegates to the Slack notifier.",
        parameters={
            "channel": {"type": "string", "description": "Slack channel (e.g., #revops-alerts)"},
            "message": {"type": "string", "description": "Alert message text"},
            "severity": {"type": "string", "description": "Severity label", "default": "info"},
            "title": {"type": "string", "description": "Optional alert title", "default": ""},
        },
        destructive=False,
        rollback_supported=False,
        requires_credentials=[],
        policy_tags=["external_notify"],
        writes_external=False,
        risk_level=1,
        risk_category="reversible_write",
        impact_tier=2,
        idempotent=False,
        blast_radius="external_side_effect",
    ),
]

# Deal Desk tools
DEALDESK_TOOLS: list[AutopilotToolDefinition] = [
    AutopilotToolDefinition(
        name="dealdesk.quote.readiness",
        category="dealdesk",
        description=(
            "Inspect the Salesforce quote environment, build historical deal patterns, "
            "and evaluate quote readiness for an Opportunity before any write action."
        ),
        cli_equivalent="g-gremlin autopilot dealdesk quote-readiness {opportunity_id} --org-alias {org_alias}",
        parameters={
            "opportunity_id": {"type": "string", "description": "Target Opportunity ID"},
            "quote_request": {
                "type": "object",
                "description": "Optional normalized quote request fields from Slack or UI intake",
                "default": {},
            },
            "config_path": {"type": "string", "description": "Optional Deal Desk config path", "default": ""},
            "state_dir": {"type": "string", "description": "Optional state directory override", "default": ""},
            "org_alias": {"type": "string", "description": "Target org alias", "default": ""},
            "force_refresh": {
                "type": "boolean",
                "description": "Rebuild org profiles even if cached artifacts already exist",
                "default": False,
            },
        },
        destructive=False,
        rollback_supported=False,
        requires_credentials=["salesforce"],
        policy_tags=["dealdesk", "read_only"],
        writes_external=False,
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="dealdesk.quote.plan",
        category="dealdesk",
        description=(
            "Build a structured Standard Quote draft plan from readiness output and explicit line-item input "
            "without creating any Salesforce records."
        ),
        cli_equivalent="g-gremlin autopilot dealdesk quote-plan {opportunity_id} --org-alias {org_alias}",
        parameters={
            "opportunity_id": {"type": "string", "description": "Target Opportunity ID"},
            "quote_request": {
                "type": "object",
                "description": (
                    "Structured quote input including explicit line_items with product_id, "
                    "product_code, or product_name references"
                ),
                "default": {},
            },
            "config_path": {"type": "string", "description": "Optional Deal Desk config path", "default": ""},
            "state_dir": {"type": "string", "description": "Optional state directory override", "default": ""},
            "org_alias": {"type": "string", "description": "Target org alias", "default": ""},
            "force_refresh": {
                "type": "boolean",
                "description": "Rebuild org profiles even if cached artifacts already exist",
                "default": False,
            },
            "allow_insufficient_evidence": {
                "type": "boolean",
                "description": (
                    "Allow controlled planning when readiness_mode is insufficient_evidence; "
                    "intended for explicit dev-org shakeout only"
                ),
                "default": False,
            },
        },
        destructive=False,
        rollback_supported=False,
        requires_credentials=["salesforce"],
        policy_tags=["dealdesk", "read_only"],
        writes_external=False,
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="dealdesk.quote.create",
        category="dealdesk",
        description=(
            "Create a single Standard Quote header from a persisted QuoteDraftPlanV1 after approval and "
            "readiness/precheck gates pass."
        ),
        cli_equivalent=(
            "g-gremlin autopilot dealdesk quote-create {opportunity_id} "
            "--org-alias {org_alias} --approved-by {approved_by}"
        ),
        parameters={
            "opportunity_id": {"type": "string", "description": "Target Opportunity ID"},
            "config_path": {"type": "string", "description": "Optional Deal Desk config path", "default": ""},
            "state_dir": {"type": "string", "description": "Optional state directory override", "default": ""},
            "org_alias": {"type": "string", "description": "Target org alias", "default": ""},
            "crm_org_id": {"type": "string", "description": "Override CRM org identifier", "default": ""},
            "approved_by": {
                "type": "string",
                "description": "Human approver identity required by QuoteDraftPlanV1",
                "default": "",
            },
            "approval_note": {
                "type": "string",
                "description": "Optional rationale attached to the quote creation approval stamp",
                "default": "",
            },
            "allow_review_required": {
                "type": "boolean",
                "description": "Allow execution when readiness_mode is review_required",
                "default": False,
            },
            "allow_insufficient_evidence": {
                "type": "boolean",
                "description": (
                    "Allow execution when readiness_mode is insufficient_evidence in controlled environments"
                ),
                "default": False,
            },
            "force_refresh": {
                "type": "boolean",
                "description": "Rebuild cached profiles before re-running create prechecks",
                "default": False,
            },
            "run_id": {"type": "string", "description": "Autopilot run ID / receipt ID", "default": ""},
        },
        destructive=False,
        rollback_supported=True,
        rollback_method="delete_before_approval_boundary",
        requires_credentials=["salesforce"],
        policy_tags=["dealdesk", "reversible_write"],
        writes_external=False,
        **{**REVERSIBLE_WRITE_META, "idempotent": False, "blast_radius": "single_record"},
    ),
    AutopilotToolDefinition(
        name="dealdesk.quote.line_items.upsert",
        category="dealdesk",
        description=(
            "Resolve PricebookEntry matches from the persisted QuoteDraftPlanV1 and insert deterministic "
            "QuoteLineItem rows onto an existing Standard Quote."
        ),
        cli_equivalent=(
            "g-gremlin autopilot dealdesk quote-line-items {quote_id} --org-alias {org_alias}"
        ),
        parameters={
            "quote_id": {"type": "string", "description": "Target Quote ID"},
            "opportunity_id": {
                "type": "string",
                "description": "Optional source Opportunity ID; inferred from the Quote when omitted",
                "default": "",
            },
            "config_path": {"type": "string", "description": "Optional Deal Desk config path", "default": ""},
            "state_dir": {"type": "string", "description": "Optional state directory override", "default": ""},
            "org_alias": {"type": "string", "description": "Target org alias", "default": ""},
            "crm_org_id": {"type": "string", "description": "Override CRM org identifier", "default": ""},
            "allow_insufficient_evidence": {
                "type": "boolean",
                "description": (
                    "Allow execution when readiness_mode is insufficient_evidence in controlled environments"
                ),
                "default": False,
            },
            "run_id": {"type": "string", "description": "Autopilot run ID / receipt ID", "default": ""},
        },
        destructive=False,
        rollback_supported=True,
        rollback_method="delete_line_items_then_quote_before_approval_boundary",
        requires_credentials=["salesforce"],
        policy_tags=["dealdesk", "reversible_write"],
        writes_external=False,
        **{**REVERSIBLE_WRITE_META, "idempotent": True, "blast_radius": "single_record"},
    ),
    AutopilotToolDefinition(
        name="dealdesk.quote.rollback",
        category="dealdesk",
        description=(
            "Delete QuoteLineItem rows and the Standard Quote header created by the Deal Desk flow "
            "before any approval workflow side effects or quote acceptance exist. "
            "Rollback acts on previously created records and does not re-evaluate readiness."
        ),
        cli_equivalent=(
            "g-gremlin autopilot dealdesk quote-rollback {quote_id} --org-alias {org_alias}"
        ),
        parameters={
            "quote_id": {"type": "string", "description": "Target Quote ID"},
            "opportunity_id": {
                "type": "string",
                "description": "Optional source Opportunity ID; inferred from the Quote when available",
                "default": "",
            },
            "rollback_data": {
                "type": "object",
                "description": "Optional rollback metadata returned by quote create or line-item upsert",
                "default": {},
            },
            "config_path": {"type": "string", "description": "Optional Deal Desk config path", "default": ""},
            "state_dir": {"type": "string", "description": "Optional state directory override", "default": ""},
            "org_alias": {"type": "string", "description": "Target org alias", "default": ""},
            "crm_org_id": {"type": "string", "description": "Override CRM org identifier", "default": ""},
            "run_id": {"type": "string", "description": "Autopilot run ID / receipt ID", "default": ""},
        },
        destructive=True,
        rollback_supported=False,
        requires_credentials=["salesforce"],
        policy_tags=["dealdesk", "rollback", "reversible_write"],
        writes_external=False,
        **{**REVERSIBLE_WRITE_META, "idempotent": True, "blast_radius": "single_record", "risk_level": 2},
    ),
    AutopilotToolDefinition(
        name="dealdesk.renewal.create_shell",
        category="dealdesk",
        description="Create a renewal opportunity shell from a Closed Won opportunity.",
        parameters={
            "record_ids": {"type": "array", "items": {"type": "string"}, "description": "Source Opportunity IDs"},
            "config_path": {"type": "string", "description": "Deal Desk config path", "default": ""},
            "org_alias": {"type": "string", "description": "Target org alias", "default": ""},
            "run_id": {"type": "string", "description": "Autopilot run ID", "default": ""},
        },
        destructive=False,
        rollback_supported=True,
        rollback_method="delete_with_provenance",
        requires_credentials=["salesforce"],
        policy_tags=["dealdesk"],
        writes_external=False,
        **{**BULK_WRITE_META, "blast_radius": "single_record"},
    ),
    AutopilotToolDefinition(
        name="dealdesk.approval.stamp",
        category="dealdesk",
        description="Stamp Deal Desk approval fields on an Opportunity.",
        parameters={
            "record_id": {"type": "string", "description": "Opportunity ID"},
            "fields": {"type": "object", "description": "Field updates", "default": {}},
            "org_alias": {"type": "string", "description": "Target org alias", "default": ""},
        },
        destructive=False,
        rollback_supported=True,
        rollback_method="snapshot",
        requires_credentials=["salesforce"],
        policy_tags=["dealdesk", "reversible_write"],
        writes_external=False,
        **{**REVERSIBLE_WRITE_META, "blast_radius": "single_record"},
    ),
]

# Define enrich tools
ENRICH_TOOLS: list[AutopilotToolDefinition] = [
    AutopilotToolDefinition(
        name="enrich",
        category="enrich",
        description="Enrich companies using the waterfall provider stack.",
        parameters={
            "column": {"type": "string", "description": "Company or domain column"},
            "fields": {
                "type": "array",
                "items": {"type": "string"},
                "description": "Fields to enrich (industry, employee_count, etc.)",
            },
        },
        cli_equivalent="g-gremlin enrich --column {column} --fields {fields}",
        destructive=False,
        preview_trustworthy=False,
        writes_external=False,
        requires_credentials=["pdl", "apollo", "clearbit"],
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="fg_parent",
        category="enrich",
        description="Resolve company to ultimate parent using FoundryGraph.",
        parameters={"column": {"type": "string", "description": "Domain or company column"}},
        cli_equivalent="g-gremlin fg parent --column {column}",
        destructive=False,
        requires_credentials=["foundrygraph"],
        **READ_ONLY_META,
    ),
]

# Define sequencer tools (external writes)
SEQUENCER_TOOLS: list[AutopilotToolDefinition] = [
    AutopilotToolDefinition(
        name="sequencer_push",
        category="sequencer",
        description="Push contacts to a sales sequence (Instantly, Smartlead, Apollo).",
        parameters={
            "provider": {"type": "string", "enum": ["instantly", "smartlead", "apollo"]},
            "campaign": {"type": "string", "description": "Campaign or sequence ID"},
        },
        cli_equivalent="g-gremlin sequencer push --provider {provider} --campaign {campaign}",
        destructive=True,
        writes_external=True,
        rollback_supported=False,
        requires_credentials=["instantly", "smartlead", "apollo"],
        policy_tags=["external_side_effects"],
        **IRREVERSIBLE_META,
    ),
]

# Architect metadata pack tools
ARCHITECT_TOOLS: list[AutopilotToolDefinition] = [
    AutopilotToolDefinition(
        name="architect.metadata_pack.plan",
        category="architect",
        description="Plan a Salesforce metadata pack deployment.",
        parameters={
            "pack_dir": {"type": "string", "description": "Path to metadata pack directory"},
            "org_alias": {"type": "string", "description": "Target org alias"},
        },
        cli_equivalent="g-gremlin sfdc metadata-pack plan {pack_dir} --org-alias {org_alias}",
        destructive=False,
        requires_credentials=["salesforce"],
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="architect.metadata_pack.apply",
        category="architect",
        description="Apply a Salesforce metadata pack deployment.",
        parameters={
            "pack_dir": {"type": "string", "description": "Path to metadata pack directory"},
            "org_alias": {"type": "string", "description": "Target org alias"},
            "yes": {"type": "boolean", "description": "Confirmation flag"},
            "check_only": {"type": "boolean", "description": "Validation-only deploy"},
            "replan": {"type": "boolean", "description": "Regenerate plan before apply"},
            "plan_path": {"type": "string", "description": "Optional plan.json path"},
        },
        cli_equivalent="g-gremlin sfdc metadata-pack apply {pack_dir} --org-alias {org_alias} --yes",
        destructive=True,
        writes_external=True,
        rollback_supported=True,
        requires_credentials=["salesforce"],
        policy_tags=["metadata_write", "architect"],
        risk_level=2,
        risk_category="metadata_write",
        blast_radius="metadata",
    ),
    AutopilotToolDefinition(
        name="architect.metadata_pack.verify",
        category="architect",
        description="Verify a Salesforce metadata pack deployment.",
        parameters={
            "pack_dir": {"type": "string", "description": "Path to metadata pack directory"},
            "org_alias": {"type": "string", "description": "Target org alias"},
        },
        cli_equivalent="g-gremlin sfdc metadata-pack verify {pack_dir} --org-alias {org_alias}",
        destructive=False,
        requires_credentials=["salesforce"],
        **READ_ONLY_META,
    ),
]

# Architect HubSpot tools
ARCHITECT_HUBSPOT_TOOLS: list[AutopilotToolDefinition] = [
    AutopilotToolDefinition(
        name="architect.hubspot_pack.plan",
        category="architect",
        description="Plan a HubSpot pack deployment.",
        parameters={
            "pack_dir": {"type": "string", "description": "Path to hubspot pack directory"},
            "hubspot_profile": {"type": "string", "description": "HubSpot profile name"},
        },
        cli_equivalent="g-gremlin hubspot pack plan {pack_dir}",
        destructive=False,
        requires_credentials=["hubspot"],
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="architect.hubspot_pack.apply",
        category="architect",
        description="Apply a HubSpot pack deployment.",
        parameters={
            "pack_dir": {"type": "string", "description": "Path to hubspot pack directory"},
            "hubspot_profile": {"type": "string", "description": "HubSpot profile name"},
            "allow_delete_stages": {"type": "boolean", "description": "Allow deleting pipeline stages"},
            "allow_archive_properties": {"type": "boolean", "description": "Allow archiving properties"},
            "allow_delete_workflows": {"type": "boolean", "description": "Allow deleting workflows"},
            "plan_path": {"type": "string", "description": "Optional plan.json path from a prior plan run"},
            "plan_hash": {"type": "string", "description": "Optional reviewed plan hash to verify before apply"},
            "replan": {"type": "boolean", "description": "Recompute plan before apply"},
        },
        cli_equivalent="g-gremlin hubspot pack apply {pack_dir} --yes [--plan-hash HASH]",
        destructive=True,
        writes_external=True,
        rollback_supported=True,
        requires_credentials=["hubspot"],
        policy_tags=["metadata_write", "architect", "hubspot"],
        risk_level=2,
        risk_category="metadata_write",
        blast_radius="metadata",
    ),
    AutopilotToolDefinition(
        name="architect.hubspot_pack.drift",
        category="architect",
        description="Compute drift for a HubSpot pack.",
        parameters={
            "pack_dir": {"type": "string", "description": "Path to hubspot pack directory"},
            "hubspot_profile": {"type": "string", "description": "HubSpot profile name"},
        },
        cli_equivalent="g-gremlin hubspot pack doctor {pack_dir} --json",
        destructive=False,
        requires_credentials=["hubspot"],
        **READ_ONLY_META,
    ),
    AutopilotToolDefinition(
        name="architect.hubspot_workflow.apply",
        category="architect",
        description="Apply HubSpot workflow definitions.",
        parameters={
            "workflows_dir": {"type": "string", "description": "Directory containing workflow JSON files"},
            "hubspot_profile": {"type": "string", "description": "HubSpot profile name"},
            "backup_dir": {"type": "string", "description": "Directory to store workflow backups"},
        },
        cli_equivalent=None,
        destructive=True,
        writes_external=True,
        rollback_supported=True,
        requires_credentials=["hubspot"],
        policy_tags=["metadata_write", "architect", "hubspot"],
        risk_level=2,
        risk_category="metadata_write",
        blast_radius="metadata",
    ),
    AutopilotToolDefinition(
        name="architect.hubspot_associate.batch",
        category="architect",
        description="Batch associate HubSpot objects.",
        parameters={
            "from_type": {"type": "string", "description": "HubSpot object type to associate from"},
            "to_type": {"type": "string", "description": "HubSpot object type to associate to"},
            "mappings": {"type": "array", "description": "List of {from_id,to_id} mappings"},
            "mappings_path": {"type": "string", "description": "Path to JSON file with mappings"},
            "hubspot_profile": {"type": "string", "description": "HubSpot profile name"},
        },
        cli_equivalent=None,
        destructive=True,
        writes_external=True,
        rollback_supported=True,
        rollback_method="dissociate",
        requires_credentials=["hubspot"],
        policy_tags=["hubspot_write", "architect", "hubspot"],
        risk_level=1,
        risk_category="reversible_write",
        blast_radius="bulk_records",
    ),
]

# All tools combined
ALL_TOOLS: list[AutopilotToolDefinition] = (
    SCOUT_TOOLS
    + TRANSFORM_TOOLS
    + MATCH_TOOLS
    + AUTOPILOT_ADMIN_TOOLS
    + ABSTRACT_ACTION_TOOLS
    + DEALDESK_TOOLS
    + ENRICH_TOOLS
    + SEQUENCER_TOOLS
    + ARCHITECT_TOOLS
    + ARCHITECT_HUBSPOT_TOOLS
)


class ToolRegistry:
    """Registry of tools available to the autopilot agent."""

    def __init__(self, available_credentials: set[str] | None = None):
        """Initialize the registry.

        Args:
            available_credentials: Set of credential types the user has configured.
                                  If None, all tools are available.
        """
        self.available_credentials = available_credentials or set()
        self._tools = {tool.name: tool for tool in ALL_TOOLS}
        self._handlers: dict[str, ToolHandler] = {}

    def get_all_tools(self) -> list[AutopilotToolDefinition]:
        """Get all registered tools."""
        return list(self._tools.values())

    def get_tool(self, name: str) -> AutopilotToolDefinition | None:
        """Get a specific tool by name."""
        return self._tools.get(name)

    def register_handler(self, tool_name: str, handler: ToolHandler) -> None:
        """Register an execution handler for a tool."""
        self._handlers[tool_name] = handler

    def get_handler(self, tool_name: str) -> ToolHandler | None:
        """Get a registered execution handler for a tool."""
        return self._handlers.get(tool_name)

    def get_tools_for_llm(self) -> list[dict[str, Any]]:
        """Get tools filtered and formatted for LLM.

        Filters out tools that require credentials the user doesn't have.
        """
        tools = []
        for tool in self._tools.values():
            # Check if user has required credentials
            if tool.requires_credentials:
                has_any_cred = any(
                    cred in self.available_credentials for cred in tool.requires_credentials
                )
                if not has_any_cred:
                    continue

            tools.append(tool.to_llm_schema(self.available_credentials))

        return tools

    def get_tools_by_category(self, category: str) -> list[AutopilotToolDefinition]:
        """Get tools by category."""
        return [tool for tool in self._tools.values() if tool.category == category]

    def get_destructive_tools(self) -> list[AutopilotToolDefinition]:
        """Get tools that are marked as destructive."""
        return [tool for tool in self._tools.values() if tool.destructive]

    def get_external_write_tools(self) -> list[AutopilotToolDefinition]:
        """Get tools that write to external systems."""
        return [tool for tool in self._tools.values() if tool.writes_external]


def get_default_registry() -> ToolRegistry:
    """Get the default tool registry with no credential filtering."""
    registry = ToolRegistry()
    try:
        from .execution_adapters import register_execution_adapters
        from .sfdc_handlers import (
            handle_add_to_queue_group,
            handle_assign_permission_set_groups,
            handle_assign_permission_sets,
            handle_architect_metadata_pack_apply,
            handle_architect_metadata_pack_plan,
            handle_architect_metadata_pack_verify,
            handle_forecast_assign_user_to_role,
            handle_sfdc_record_create,
            handle_sfdc_record_delete,
            handle_sfdc_record_enrich_missing_fields,
            handle_sfdc_followup_enforce,
            handle_sfdc_record_update,
            handle_sfdc_record_reassign_owner,
            handle_sfdc_user_deactivate,
            handle_scout_automation_failure_impact,
            handle_scout_forecast_hierarchy_drift,
            handle_scout_integration_health,
            handle_scout_license_utilization,
            handle_scout_lead_to_account_match_health,
            handle_scout_user_provisioning_parity,
            handle_scout_workflow_impact,
            handle_sequence_pause,
            handle_slack_notify,
            handle_tasks_create,
        )
        from g_gremlin.dealdesk.handlers import (
            handle_dealdesk_approval_stamp,
            handle_dealdesk_quote_readiness,
            handle_dealdesk_renewal_create_shell,
        )
        from g_gremlin.dealdesk.quote_handlers import (
            handle_dealdesk_quote_create,
            handle_dealdesk_quote_line_items_upsert,
            handle_dealdesk_quote_plan,
            handle_dealdesk_quote_rollback,
        )
        from .hubspot_handlers import (
            handle_hubspot_associate_batch,
            handle_hubspot_pack_apply,
            handle_hubspot_pack_drift,
            handle_hubspot_pack_plan,
            handle_hubspot_workflow_apply,
        )
    except Exception:
        return registry
    registry.register_handler("sfdc.user.assign_permission_sets", handle_assign_permission_sets)
    registry.register_handler("sfdc.user.assign_permission_set_groups", handle_assign_permission_set_groups)
    registry.register_handler("sfdc.user.add_to_queue_group", handle_add_to_queue_group)
    registry.register_handler("sfdc.user.deactivate", handle_sfdc_user_deactivate)
    registry.register_handler("sfdc.record.create", handle_sfdc_record_create)
    registry.register_handler("sfdc.record.update", handle_sfdc_record_update)
    registry.register_handler("sfdc.record.delete", handle_sfdc_record_delete)
    registry.register_handler("sfdc.record.enrich_missing_fields", handle_sfdc_record_enrich_missing_fields)
    registry.register_handler("sfdc.followup.enforce", handle_sfdc_followup_enforce)
    registry.register_handler("sfdc.record.reassign_owner", handle_sfdc_record_reassign_owner)
    registry.register_handler("sfdc.forecast.assign_user_to_role", handle_forecast_assign_user_to_role)
    registry.register_handler("architect.metadata_pack.plan", handle_architect_metadata_pack_plan)
    registry.register_handler("architect.metadata_pack.apply", handle_architect_metadata_pack_apply)
    registry.register_handler("architect.metadata_pack.verify", handle_architect_metadata_pack_verify)
    registry.register_handler("architect.hubspot_pack.plan", handle_hubspot_pack_plan)
    registry.register_handler("architect.hubspot_pack.apply", handle_hubspot_pack_apply)
    registry.register_handler("architect.hubspot_pack.drift", handle_hubspot_pack_drift)
    registry.register_handler("architect.hubspot_workflow.apply", handle_hubspot_workflow_apply)
    registry.register_handler("architect.hubspot_associate.batch", handle_hubspot_associate_batch)
    registry.register_handler("scout.automation_failure_impact", handle_scout_automation_failure_impact)
    registry.register_handler("scout.forecast_hierarchy_drift", handle_scout_forecast_hierarchy_drift)
    registry.register_handler("scout.integration_health", handle_scout_integration_health)
    registry.register_handler("scout.license_utilization", handle_scout_license_utilization)
    registry.register_handler("scout.lead_to_account_match_health", handle_scout_lead_to_account_match_health)
    registry.register_handler("scout.user_provisioning_parity", handle_scout_user_provisioning_parity)
    registry.register_handler("scout.workflow_impact", handle_scout_workflow_impact)
    registry.register_handler("sequence.pause", handle_sequence_pause)
    registry.register_handler("slack.notify", handle_slack_notify)
    registry.register_handler("tasks.create", handle_tasks_create)
    registry.register_handler("dealdesk.quote.readiness", handle_dealdesk_quote_readiness)
    registry.register_handler("dealdesk.quote.plan", handle_dealdesk_quote_plan)
    registry.register_handler("dealdesk.quote.create", handle_dealdesk_quote_create)
    registry.register_handler("dealdesk.quote.line_items.upsert", handle_dealdesk_quote_line_items_upsert)
    registry.register_handler("dealdesk.quote.rollback", handle_dealdesk_quote_rollback)
    registry.register_handler("dealdesk.renewal.create_shell", handle_dealdesk_renewal_create_shell)
    registry.register_handler("dealdesk.approval.stamp", handle_dealdesk_approval_stamp)
    register_execution_adapters(registry)
    return registry


def get_registry_for_user(credential_types: set[str]) -> ToolRegistry:
    """Get a tool registry filtered by user's available credentials.

    Args:
        credential_types: Set of credential types the user has configured
                         (e.g., {"google", "salesforce", "hubspot"})
    """
    return ToolRegistry(available_credentials=credential_types)
