# Copyright (c) 2025 Airbyte, Inc., all rights reserved.
"""MCP tool for on-demand Devin secret request.

The tool operates in two phases:

1. **Request** (no `approval_evidence_url`): Sends a Slack approval
   request via the existing human-in-the-loop infrastructure.
2. **Deliver** (with `approval_evidence_url`): Triggers a GitHub
   Actions workflow that reads the secret from 1Password and sends
   a time-limited share link to the session via `aaronsteers/devin-action`.
   The agent opens the link in a browser to view and copy the secret.
"""

# NOTE: We intentionally do NOT use `from __future__ import annotations` here.
# FastMCP has issues resolving forward references when PEP 563 deferred annotations
# are used. See: https://github.com/jlowin/fastmcp/issues/905

import re
from typing import Annotated

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

from airbyte_ops_mcp.github_actions import trigger_workflow_dispatch
from airbyte_ops_mcp.github_api import resolve_github_token
from airbyte_ops_mcp.human_in_the_loop import dispatch_escalation

# ---------------------------------------------------------------------------
# Constants
# ---------------------------------------------------------------------------

WORKFLOW_REPO_OWNER = "airbytehq"
WORKFLOW_REPO_NAME = "airbyte-ops-mcp"
WORKFLOW_FILE = "devin-secret-request.yml"
WORKFLOW_DEFAULT_BRANCH = "main"

WORKFLOW_TRIGGER_TOKEN_ENV_VARS = [
    "GITHUB_CI_WORKFLOW_TRIGGER_PAT",
    "GITHUB_TOKEN",
]

SECRET_REQUEST_CHANNEL = "human-in-the-loop"

_SESSION_ID_PATTERN = re.compile(r"[0-9a-fA-F]{32}")


class SecretRequestResponse(BaseModel):
    """Response from the request_devin_secret tool."""

    success: bool = Field(description="Whether the operation succeeded")
    phase: str = Field(
        description=(
            "Current phase: 'approval_requested' (Phase 1) or "
            "'delivery_dispatched' (Phase 2)"
        ),
    )
    message: str = Field(description="Human-readable status message")
    secret_alias: str = Field(description="The requested secret alias")
    session_id: str = Field(description="The Devin session ID")
    workflow_url: str | None = Field(
        default=None,
        description="URL to the GitHub Actions workflow",
    )
    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",
    )
    request_id: str | None = Field(
        default=None,
        description=(
            "Unique request identifier (UUIDv7). Returned in Phase 1; "
            "pass it back in Phase 2 for replay-protection validation."
        ),
    )


@mcp_tool(
    read_only=False,
    idempotent=False,
    open_world=True,
)
def request_devin_secret(
    secret_alias: Annotated[
        str,
        "The name of the secret to request. This must exactly match an item "
        "title in the 'devin-on-demand-secrets' 1Password vault.",
    ],
    session_url: Annotated[
        str,
        "Your Devin session URL (e.g. 'https://app.devin.ai/sessions/abc123...'). "
        "Use the session URL from your system prompt.",
    ],
    approval_evidence_url: Annotated[
        str | None,
        "Slack approval record URL "
        "(https://<workspace>.slack.com/archives/...). "
        "Leave empty for Phase 1 (requesting approval). Provide the "
        "Slack URL for Phase 2 (delivering the secret after approval).",
    ] = None,
    target_approver: Annotated[
        str | None,
        "Person to notify for approval (GitHub handle, email, or Slack user ID). "
        "Required for Phase 1 (approval request).",
    ] = None,
    request_id: Annotated[
        str | None,
        "Request ID returned by Phase 1 (UUIDv7). Pass it back in Phase 2 "
        "so the approval record can be validated against the original request. "
        "Leave empty for Phase 1.",
    ] = None,
) -> SecretRequestResponse:
    """Request a secret on demand via an approval workflow.

    This tool operates in two phases:

    **Phase 1** (no approval_evidence_url): Sends a Slack approval
    request. The approver sees which secret is requested and for which
    session. Returns immediately after dispatching the request.

    **Phase 2** (with approval_evidence_url): After a human approves the
    request, call this tool again with the approval evidence URL. This
    triggers a GitHub Actions workflow that reads the secret from
    1Password and sends you a time-limited share link.
    Open the link in your browser to view and copy the secret.

    Typical workflow:
    1. Call this tool without approval_evidence_url to request approval.
    2. Note the ``request_id`` in the response.
    3. Wait for a human to approve the request in Slack.
    4. Obtain the approval evidence URL (Slack approval record URL).
    5. Call this tool again with the approval_evidence_url **and** the
       request_id from step 2.
    6. You will receive a 1Password share link -- open it in your
       browser to view and copy the secret values.
    """
    # Extract session ID from URL
    match = _SESSION_ID_PATTERN.search(session_url)
    if not match:
        return SecretRequestResponse(
            success=False,
            phase="error",
            message=(
                f"No valid session ID found in URL: {session_url}. "
                "Expected a 32-character hex string."
            ),
            secret_alias=secret_alias,
            session_id="",
        )
    session_id = match.group(0)
    short_session = session_id[:8]

    if not approval_evidence_url:
        # Phase 1: Request approval via Slack
        if not target_approver:
            return SecretRequestResponse(
                success=False,
                phase="error",
                message=(
                    "target_approver is required when requesting approval "
                    "(no approval_evidence_url provided)."
                ),
                secret_alias=secret_alias,
                session_id=session_id,
            )
        approver = target_approver
        generated_request_id = uuid7str()

        result = dispatch_escalation(
            target_person=approver,
            message=(
                f"*Secret access requested:* `{secret_alias}`\n"
                f"*Requesting session:* `{short_session}...`\n\n"
                f"A Devin session is requesting access to the "
                f"`{secret_alias}` secret. If approved, a time-limited "
                f"1Password share link will be sent to the requesting "
                f"session.\n\n"
                f"Please review and approve or reject this request."
            ),
            agent_session_url=session_url,
            approval_requested=True,
            approval_request_summary=(
                f"Grant access to secret `{secret_alias}` "
                f"for Devin session {short_session}"
            ),
            approval_metadata={
                "secret_alias": secret_alias,
                "request_id": generated_request_id,
            },
            channel_override=SECRET_REQUEST_CHANNEL,
            header_emoji="🔑",
            header_label="Secret Access Request",
        )

        view_url = result.run_url or result.workflow_url
        return SecretRequestResponse(
            success=True,
            phase="approval_requested",
            message=(
                f"Approval request for secret '{secret_alias}' sent to "
                f"#human-in-the-loop. Waiting for human approval. "
                f"Once approved, call this tool again with the "
                f"approval_evidence_url to deliver the secret. "
                f"View progress: {view_url}"
            ),
            secret_alias=secret_alias,
            session_id=session_id,
            workflow_url=result.workflow_url,
            run_id=result.run_id,
            run_url=result.run_url,
            request_id=generated_request_id,
        )

    # Phase 2: Deliver secret via GitHub Actions workflow
    token = resolve_github_token(preferred_env_vars=WORKFLOW_TRIGGER_TOKEN_ENV_VARS)

    workflow_inputs: dict[str, str] = {
        "secret_alias": secret_alias,
        "session_id": session_id,
        "approval_evidence_url": approval_evidence_url,
    }
    if request_id:
        workflow_inputs["expected_request_id"] = request_id

    result = trigger_workflow_dispatch(
        owner=WORKFLOW_REPO_OWNER,
        repo=WORKFLOW_REPO_NAME,
        workflow_file=WORKFLOW_FILE,
        ref=WORKFLOW_DEFAULT_BRANCH,
        inputs=workflow_inputs,
        token=token,
    )

    view_url = result.run_url or result.workflow_url
    return SecretRequestResponse(
        success=True,
        phase="delivery_dispatched",
        message=(
            f"Secret delivery workflow dispatched for '{secret_alias}'. "
            f"The workflow will read the secret from 1Password and send "
            f"you a time-limited share link. Once you receive the link, "
            f"open it in your browser to view and copy the secret. "
            f"View progress: {view_url}"
        ),
        secret_alias=secret_alias,
        session_id=session_id,
        workflow_url=result.workflow_url,
        run_id=result.run_id,
        run_url=result.run_url,
        request_id=request_id,
    )


def register_devin_secret_request_tools(app: FastMCP) -> None:
    """Register Devin secret request tools with the FastMCP app."""
    register_mcp_tools(app, mcp_module=__name__)
