# Copyright (c) 2025 Airbyte, Inc., all rights reserved.
"""MCP tool for human-in-the-loop escalation.

This module exposes the HITL escalation operation as an MCP tool for AI agents.
It is a thin wrapper around the core dispatch function in human_in_the_loop module.
"""

from __future__ import annotations

import logging
from typing import Annotated

from fastmcp import FastMCP
from fastmcp_extensions import mcp_tool, register_mcp_tools
from pydantic import BaseModel, Field

from airbyte_ops_mcp.human_in_the_loop import dispatch_escalation

logger = logging.getLogger(__name__)


class EscalateToHumanResponse(BaseModel):
    """Response from the human-in-the-loop escalation tool."""

    success: bool = Field(description="Whether the workflow was triggered successfully")
    message: str = Field(description="Human-readable status message")
    workflow_url: str | None = Field(
        default=None,
        description="URL to view the GitHub Actions workflow file",
    )
    run_id: int | None = Field(
        default=None,
        description="GitHub Actions workflow run ID",
    )
    run_url: str | None = Field(
        default=None,
        description="Direct URL to the GitHub Actions workflow run",
    )


@mcp_tool(
    read_only=False,
    idempotent=False,
    open_world=True,
)
def escalate_to_human(
    target_person: Annotated[
        str,
        "Primary person to notify. Accepts an email address (e.g. 'aj@airbyte.io'), "
        "a GitHub handle prefixed with @ (e.g. '@aaronsteers'), "
        "or a Slack user ID (e.g. 'U05AKF1BCC9').",
    ],
    message: Annotated[
        str,
        "The message body to deliver to the human. Format using Slack mrkdwn: "
        "*bold*, _italic_, `code`, ```code blocks```, > blockquotes, "
        "- bullet lists, and <url|label> links. Should clearly explain "
        "what you need help with or what decision is required.",
    ],
    agent_session_url: Annotated[
        str,
        "Your agent session URL so the human can view the full context. "
        "Use the session URL from your system prompt.",
    ],
    cc: Annotated[
        list[str] | None,
        "Optional list of additional people to tag on the message. "
        "Each entry uses the same identifier format as target_person.",
    ] = None,
    pr_url: Annotated[
        str | None,
        "Optional URL to a related pull request for the 'View PR' button.",
    ] = None,
    issue_url: Annotated[
        str | None,
        "Optional URL to a related GitHub issue for the 'View Issue' button.",
    ] = None,
    additional_actions: Annotated[
        dict[str, str] | None,
        "Optional dictionary of label -> URL pairs for extra action buttons. "
        "Example: {'Start Workflow': 'https://github.com/...actions/...'}.",
    ] = None,
    connector_name: Annotated[
        str | None,
        "Optional connector name to include in the message header as 'Re: {connector_name}'. "
        "Example: 'source-salesloft'.",
    ] = None,
) -> EscalateToHumanResponse:
    """Escalate to a human team member via Slack.

    Posts a formatted message to the #human-in-the-loop Slack channel,
    tagging the specified person(s). The message includes clickable buttons
    for the Devin session, PR, and issue links when provided, plus any
    additional freeform action buttons.

    The Slack message is sent by a GitHub Actions workflow so that Slack
    credentials are never exposed to the calling agent. The workflow
    resolves person identifiers (email, GitHub handle, or Slack ID) to
    Slack user IDs using the internal team roster.

    Use this tool when you need human input, approval, or help that you
    cannot resolve on your own.
    """
    try:
        result = dispatch_escalation(
            target_person=target_person,
            message=message,
            agent_session_url=agent_session_url,
            cc=cc,
            pr_url=pr_url,
            issue_url=issue_url,
            additional_actions=additional_actions,
            connector_name=connector_name,
        )
    except Exception as e:
        logger.exception("Failed to dispatch HITL escalation workflow")
        return EscalateToHumanResponse(
            success=False,
            message=f"Failed to trigger escalation workflow: {e}",
        )

    view_url = result.run_url or result.workflow_url
    return EscalateToHumanResponse(
        success=True,
        message=(
            f"Escalation sent to '{target_person}' via #human-in-the-loop. "
            f"View progress at: {view_url}"
        ),
        workflow_url=result.workflow_url,
        run_id=result.run_id,
        run_url=result.run_url,
    )


def register_human_in_the_loop_tools(app: FastMCP) -> None:
    """Register human-in-the-loop tools with the FastMCP app."""
    register_mcp_tools(app, mcp_module=__name__)
