"""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"],
    "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 canonical https URLs.",
        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 title/department/seniority.",
        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.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.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"],
        default_prechecks=["sfdc.user.exists"],
        default_postchecks=["tasks.created"],
        writes_external=False,
        **REVERSIBLE_WRITE_META,
    ),
    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",
    ),
]

# Deal Desk tools
DEALDESK_TOOLS: list[AutopilotToolDefinition] = [
    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"},
            "replan": {"type": "boolean", "description": "Recompute plan before apply"},
        },
        cli_equivalent="g-gremlin hubspot pack apply {pack_dir} --yes",
        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
    + 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 .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_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_slack_notify,
            handle_tasks_create,
        )
        from g_gremlin.dealdesk.handlers import (
            handle_dealdesk_approval_stamp,
            handle_dealdesk_renewal_create_shell,
        )
        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.update", handle_sfdc_record_update)
    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("slack.notify", handle_slack_notify)
    registry.register_handler("tasks.create", handle_tasks_create)
    registry.register_handler("dealdesk.renewal.create_shell", handle_dealdesk_renewal_create_shell)
    registry.register_handler("dealdesk.approval.stamp", handle_dealdesk_approval_stamp)
    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)
