"""
Alert Sender Tools for Autonomous Agent

Provides notification and alerting capabilities:
- Send alerts to various channels (Slack, Email, etc.)
- Log events for audit trail
- Request human approval for critical actions
"""

from __future__ import annotations

import json
import logging
from datetime import datetime, timezone
from typing import Any
from uuid import uuid4

from ..types import (
    AgentDecision,
    ApprovalRequest,
    ApprovalStatus,
    AgentPriority,
    HUMAN_APPROVAL_REQUIRED,
)

logger = logging.getLogger(__name__)


class AlertSenderTools:
    """
    Alert and notification tools for the autonomous agent

    Token consumption: 0 (pure Python)
    """

    def __init__(
        self,
        slack_webhook_url: str | None = None,
        email_config: dict[str, Any] | None = None,
    ):
        self.slack_webhook_url = slack_webhook_url
        self.email_config = email_config

        # In-memory approval queue (in production, use Redis or database)
        self._pending_approvals: dict[str, ApprovalRequest] = {}

        # Audit log
        self._audit_log: list[dict[str, Any]] = []

    # ========================================================================
    # Alert Sending
    # ========================================================================

    async def send_alert(
        self,
        message: str,
        severity: str = "info",
        channel: str = "log",
        metadata: dict[str, Any] | None = None,
    ) -> dict[str, Any]:
        """
        Send an alert through the specified channel

        Args:
            message: Alert message
            severity: Alert severity (info, warning, error, critical)
            channel: Notification channel (log, slack, email)
            metadata: Additional context

        Returns:
            Alert result
        """
        alert_id = str(uuid4())[:8]
        timestamp = datetime.now(timezone.utc)

        alert_data = {
            "alert_id": alert_id,
            "message": message,
            "severity": severity,
            "channel": channel,
            "metadata": metadata or {},
            "timestamp": timestamp.isoformat(),
        }

        # Log to audit trail
        self._log_event("alert_sent", alert_data)

        # Send based on channel
        if channel == "log":
            self._send_to_log(message, severity)
            return {"success": True, **alert_data}

        elif channel == "slack":
            if self.slack_webhook_url:
                success = await self._send_to_slack(message, severity, metadata)
                return {"success": success, **alert_data}
            else:
                # Fallback to log
                self._send_to_log(f"[SLACK] {message}", severity)
                return {"success": True, "fallback": "log", **alert_data}

        elif channel == "email":
            if self.email_config:
                success = await self._send_email(message, severity, metadata)
                return {"success": success, **alert_data}
            else:
                self._send_to_log(f"[EMAIL] {message}", severity)
                return {"success": True, "fallback": "log", **alert_data}

        else:
            self._send_to_log(message, severity)
            return {"success": True, **alert_data}

    def _send_to_log(self, message: str, severity: str):
        """Send alert to logging system"""
        log_level = {
            "info": logging.INFO,
            "warning": logging.WARNING,
            "error": logging.ERROR,
            "critical": logging.CRITICAL,
        }.get(severity, logging.INFO)

        logger.log(log_level, f"[AGENT ALERT] {message}")

    async def _send_to_slack(
        self,
        message: str,
        severity: str,
        metadata: dict[str, Any] | None
    ) -> bool:
        """Send alert to Slack webhook"""
        try:
            import httpx

            # Format Slack message
            color = {
                "info": "#36a64f",
                "warning": "#ff9800",
                "error": "#f44336",
                "critical": "#9c27b0",
            }.get(severity, "#808080")

            payload = {
                "attachments": [{
                    "color": color,
                    "title": f"🤖 Data Factory Agent Alert [{severity.upper()}]",
                    "text": message,
                    "fields": [
                        {"title": k, "value": str(v), "short": True}
                        for k, v in (metadata or {}).items()
                    ],
                    "ts": datetime.now(timezone.utc).timestamp(),
                }]
            }

            async with httpx.AsyncClient() as client:
                response = await client.post(
                    self.slack_webhook_url,
                    json=payload,
                    timeout=10.0
                )
                return response.status_code == 200

        except Exception as e:
            logger.error(f"Failed to send Slack alert: {e}")
            return False

    async def _send_email(
        self,
        message: str,
        severity: str,
        metadata: dict[str, Any] | None
    ) -> bool:
        """Send alert via email (placeholder)"""
        # In production, implement email sending
        logger.info(f"[EMAIL ALERT] {severity}: {message}")
        return True

    # ========================================================================
    # Human Approval
    # ========================================================================

    def check_requires_approval(self, action: str, parameters: dict[str, Any]) -> bool:
        """
        Check if an action requires human approval

        Args:
            action: The action to perform
            parameters: Action parameters

        Returns:
            True if approval required
        """
        action_upper = action.upper()

        # Check against red lines
        for red_line in HUMAN_APPROVAL_REQUIRED:
            if red_line.upper() in action_upper:
                return True

        # Check for destructive operations
        if any(kw in action_upper for kw in ["DELETE", "DROP", "TRUNCATE", "REMOVE"]):
            return True

        # Check for high-impact parameters
        if parameters.get("impact_count", 0) > 3:
            return True

        if parameters.get("cost_multiplier", 1.0) > 1.5:
            return True

        return False

    async def request_human_approval(
        self,
        decision: AgentDecision,
        expires_in_hours: int = 24,
    ) -> ApprovalRequest:
        """
        Request human approval for a critical action

        Args:
            decision: The decision requiring approval
            expires_in_hours: Hours until request expires

        Returns:
            ApprovalRequest object
        """
        request_id = str(uuid4())[:8]

        from datetime import timedelta
        expires_at = datetime.now(timezone.utc) + timedelta(hours=expires_in_hours)

        approval = ApprovalRequest(
            request_id=request_id,
            decision=decision,
            status=ApprovalStatus.PENDING,
            requester="MasterOrchestratorAgent",
            expires_at=expires_at,
        )

        # Store in pending queue
        self._pending_approvals[request_id] = approval

        # Log event
        self._log_event("approval_requested", {
            "request_id": request_id,
            "action": decision.action,
            "reason": decision.reason,
            "priority": decision.priority.value,
            "expires_at": expires_at.isoformat(),
        })

        # Send alert
        await self.send_alert(
            message=f"🔔 Approval Required: {decision.action}\n"
                    f"Reason: {decision.reason}\n"
                    f"Priority: {decision.priority.value}\n"
                    f"Request ID: {request_id}",
            severity="warning",
            channel="slack",
            metadata={
                "request_id": request_id,
                "action": decision.action,
            }
        )

        return approval

    def approve_request(
        self,
        request_id: str,
        approver: str,
        notes: str = ""
    ) -> ApprovalRequest | None:
        """Approve a pending request"""
        approval = self._pending_approvals.get(request_id)

        if not approval:
            return None

        approval.status = ApprovalStatus.APPROVED
        approval.approver = approver
        approval.notes = notes
        approval.resolved_at = datetime.now(timezone.utc)

        self._log_event("approval_granted", {
            "request_id": request_id,
            "approver": approver,
            "notes": notes,
        })

        return approval

    def reject_request(
        self,
        request_id: str,
        rejector: str,
        reason: str = ""
    ) -> ApprovalRequest | None:
        """Reject a pending request"""
        approval = self._pending_approvals.get(request_id)

        if not approval:
            return None

        approval.status = ApprovalStatus.REJECTED
        approval.approver = rejector
        approval.notes = reason
        approval.resolved_at = datetime.now(timezone.utc)

        self._log_event("approval_rejected", {
            "request_id": request_id,
            "rejector": rejector,
            "reason": reason,
        })

        return approval

    def get_pending_approvals(self) -> list[ApprovalRequest]:
        """Get all pending approval requests"""
        now = datetime.now(timezone.utc)

        pending = []
        for request in self._pending_approvals.values():
            if request.status == ApprovalStatus.PENDING:
                # Check if expired
                if request.expires_at and request.expires_at < now:
                    request.status = ApprovalStatus.EXPIRED
                else:
                    pending.append(request)

        return pending

    # ========================================================================
    # Audit Logging
    # ========================================================================

    def _log_event(self, event_type: str, data: dict[str, Any]):
        """Log an event to the audit trail"""
        event = {
            "event_id": str(uuid4())[:8],
            "event_type": event_type,
            "data": data,
            "timestamp": datetime.now(timezone.utc).isoformat(),
        }

        self._audit_log.append(event)
        logger.info(f"[AUDIT] {event_type}: {json.dumps(data)}")

        # Keep only last 1000 events in memory
        if len(self._audit_log) > 1000:
            self._audit_log = self._audit_log[-1000:]

    def get_audit_log(self, limit: int = 100) -> list[dict[str, Any]]:
        """Get recent audit log entries"""
        return self._audit_log[-limit:]


# Tool definitions for Claude Agent SDK
ALERT_SENDER_TOOLS = [
    {
        "name": "send_alert",
        "description": "Send an alert notification through the specified channel (log, slack, email).",
        "input_schema": {
            "type": "object",
            "properties": {
                "message": {
                    "type": "string",
                    "description": "Alert message content",
                },
                "severity": {
                    "type": "string",
                    "description": "Alert severity level",
                    "enum": ["info", "warning", "error", "critical"],
                    "default": "info",
                },
                "channel": {
                    "type": "string",
                    "description": "Notification channel",
                    "enum": ["log", "slack", "email"],
                    "default": "log",
                },
            },
            "required": ["message"]
        }
    },
    {
        "name": "request_human_approval",
        "description": "Request human approval for a critical action. Use this for destructive operations or actions that exceed safety thresholds.",
        "input_schema": {
            "type": "object",
            "properties": {
                "action": {
                    "type": "string",
                    "description": "The action requiring approval",
                },
                "reason": {
                    "type": "string",
                    "description": "Why this action is needed",
                },
                "priority": {
                    "type": "string",
                    "description": "Action priority",
                    "enum": ["low", "medium", "high", "critical"],
                },
                "estimated_impact": {
                    "type": "string",
                    "description": "Estimated impact of the action",
                },
            },
            "required": ["action", "reason", "priority"]
        }
    },
    {
        "name": "get_pending_approvals",
        "description": "Get list of pending approval requests.",
        "input_schema": {
            "type": "object",
            "properties": {},
            "required": []
        }
    },
    {
        "name": "get_audit_log",
        "description": "Get recent audit log entries for review.",
        "input_schema": {
            "type": "object",
            "properties": {
                "limit": {
                    "type": "integer",
                    "description": "Maximum number of entries to return",
                    "default": 100,
                },
            },
            "required": []
        }
    },
]
