"""Execution adapter layer for abstract Autopilot tool names."""

from __future__ import annotations

from typing import Any

from .contracts import PlanStep
from .tools import AutopilotToolDefinition, ToolHandler, ToolRegistry


def _delegate_handler(registry: ToolRegistry, delegate_tool: str) -> ToolHandler:
    handler = registry.get_handler(delegate_tool)
    if handler is None:
        raise RuntimeError(f"Delegate handler not registered: {delegate_tool}")
    return handler


def _delegate_step(
    step: PlanStep,
    *,
    delegate_tool: str,
    delegate_args: dict[str, Any],
) -> PlanStep:
    return step.model_copy(update={"tool": delegate_tool, "args": delegate_args})


def _with_delegation(result: dict[str, Any], delegate_tool: str) -> dict[str, Any]:
    payload = dict(result)
    after_payload = payload.get("after")
    if isinstance(after_payload, dict):
        after = dict(after_payload)
    elif after_payload is None:
        after = {}
    else:
        after = {"delegate_result": after_payload}
    after["delegated_to"] = delegate_tool
    payload["after"] = after
    payload["delegated_to"] = delegate_tool
    return payload


def _make_user_offboard_adapter(registry: ToolRegistry) -> ToolHandler:
    def _adapter(step: PlanStep, tool_def: AutopilotToolDefinition | None) -> dict[str, Any]:
        del tool_def
        delegate_args = dict(step.args or {})
        record_ids = delegate_args.get("record_ids")
        if isinstance(record_ids, list):
            delegate_args["record_ids"] = record_ids
        scout_name = delegate_args.get("scout_name")
        if scout_name is not None:
            delegate_args["scout_name"] = scout_name

        offboard_action = str(delegate_args.get("offboard_action") or "deactivate").strip().lower()
        delegate_tool = (
            "sfdc.record.reassign_owner" if offboard_action == "reassign_owner" else "sfdc.user.deactivate"
        )
        delegate = _delegate_handler(registry, delegate_tool)
        delegated_step = _delegate_step(step, delegate_tool=delegate_tool, delegate_args=delegate_args)
        delegate_tool_def = registry.get_tool(delegate_tool)
        result = delegate(delegated_step, delegate_tool_def)
        return _with_delegation(result, delegate_tool)

    return _adapter


def _make_record_enrich_adapter(registry: ToolRegistry) -> ToolHandler:
    def _adapter(step: PlanStep, tool_def: AutopilotToolDefinition | None) -> dict[str, Any]:
        del tool_def
        delegate_tool = "sfdc.record.enrich_missing_fields"
        delegate = _delegate_handler(registry, delegate_tool)
        delegate_args = dict(step.args or {})
        if "target_fields" not in delegate_args and isinstance(delegate_args.get("fields_to_enrich"), list):
            delegate_args["target_fields"] = list(delegate_args.get("fields_to_enrich") or [])
        delegated_step = _delegate_step(step, delegate_tool=delegate_tool, delegate_args=delegate_args)
        delegate_tool_def = registry.get_tool(delegate_tool)
        result = delegate(delegated_step, delegate_tool_def)
        return _with_delegation(result, delegate_tool)

    return _adapter


def _make_followup_enforce_adapter(registry: ToolRegistry) -> ToolHandler:
    def _adapter(step: PlanStep, tool_def: AutopilotToolDefinition | None) -> dict[str, Any]:
        del tool_def
        delegate_tool = "sfdc.followup.enforce"
        delegate = _delegate_handler(registry, delegate_tool)
        delegate_args = dict(step.args or {})
        delegated_step = _delegate_step(step, delegate_tool=delegate_tool, delegate_args=delegate_args)
        delegate_tool_def = registry.get_tool(delegate_tool)
        result = delegate(delegated_step, delegate_tool_def)
        return _with_delegation(result, delegate_tool)

    return _adapter


def _make_notification_slack_adapter(registry: ToolRegistry) -> ToolHandler:
    def _adapter(step: PlanStep, tool_def: AutopilotToolDefinition | None) -> dict[str, Any]:
        del tool_def
        delegate_tool = "slack.notify"
        delegate = _delegate_handler(registry, delegate_tool)

        args = dict(step.args or {})
        delegate_args: dict[str, Any] = dict(args)
        if "channel" in args:
            delegate_args["channel"] = args.get("channel")
        if "message" in args:
            delegate_args["message"] = args.get("message")
        if "scout_name" in args:
            delegate_args["scout_name"] = args.get("scout_name")

        records = args.get("records") if isinstance(args.get("records"), list) else []
        record_ids = args.get("record_ids") if isinstance(args.get("record_ids"), list) else []
        if not records and record_ids:
            records = [
                {"record_id": str(record_id).strip(), "sobject": "Record", "fields": {}}
                for record_id in record_ids
                if str(record_id).strip()
            ]
        if records:
            delegate_args["records"] = records

        delegated_step = _delegate_step(step, delegate_tool=delegate_tool, delegate_args=delegate_args)
        delegate_tool_def = registry.get_tool(delegate_tool)
        result = delegate(delegated_step, delegate_tool_def)
        return _with_delegation(result, delegate_tool)

    return _adapter


def register_execution_adapters(registry: ToolRegistry) -> None:
    """Register abstract action handlers that delegate to CRM-specific handlers."""

    registry.register_handler("user.offboard", _make_user_offboard_adapter(registry))
    registry.register_handler("record.enrich", _make_record_enrich_adapter(registry))
    registry.register_handler("meeting.followup.enforce", _make_followup_enforce_adapter(registry))
    registry.register_handler("notification.slack", _make_notification_slack_adapter(registry))


__all__ = ["register_execution_adapters"]
