"""Base handler patterns for different runtimes.

This module provides base classes for building handlers
for Lambda, FastAPI, Flask, and other runtimes.
"""

import json
import logging
from abc import ABC, abstractmethod
from typing import Any, Dict, Optional

from agent_factory.core.orchestrator import AgentOrchestrator

logger = logging.getLogger(__name__)


class BaseHandler(ABC):
    """Abstract base class for request handlers.

    Inherit from this class to create handlers for different
    runtime environments.
    """

    def __init__(self, orchestrator: AgentOrchestrator):
        """Initialize the handler.

        Args:
            orchestrator: Agent orchestrator instance
        """
        self.orchestrator = orchestrator

    @abstractmethod
    def handle(self, event: Dict[str, Any]) -> Dict[str, Any]:
        """Handle an incoming request.

        Args:
            event: Request event

        Returns:
            Response dictionary
        """
        pass


class LambdaHandler(BaseHandler):
    """Handler for AWS Lambda functions.

    Provides utilities for handling Lambda events from
    API Gateway, SQS, EventBridge, etc.

    Example:
        from agent_factory import AgentOrchestrator
        from agent_factory.models import BedrockModel
        from agent_factory.handlers import LambdaHandler

        orchestrator = AgentOrchestrator(model=BedrockModel())
        handler = LambdaHandler(orchestrator)

        def lambda_handler(event, context):
            return handler.handle(event)
    """

    def handle(self, event: Dict[str, Any]) -> Dict[str, Any]:
        """Handle a Lambda event.

        Automatically detects the event source and routes accordingly.

        Args:
            event: Lambda event

        Returns:
            Lambda response
        """
        # Detect event type
        if self._is_api_gateway_event(event):
            return self._handle_api_gateway(event)
        elif self._is_sqs_event(event):
            return self._handle_sqs(event)
        elif self._is_eventbridge_event(event):
            return self._handle_eventbridge(event)
        else:
            return self._handle_direct(event)

    def _is_api_gateway_event(self, event: Dict[str, Any]) -> bool:
        """Check if event is from API Gateway."""
        return "httpMethod" in event or "requestContext" in event

    def _is_sqs_event(self, event: Dict[str, Any]) -> bool:
        """Check if event is from SQS."""
        return "Records" in event and event.get("Records", [{}])[0].get("eventSource") == "aws:sqs"

    def _is_eventbridge_event(self, event: Dict[str, Any]) -> bool:
        """Check if event is from EventBridge."""
        return "source" in event and "detail-type" in event

    def _handle_api_gateway(self, event: Dict[str, Any]) -> Dict[str, Any]:
        """Handle API Gateway event."""
        try:
            # Parse body
            body = event.get("body", "{}")
            if isinstance(body, str):
                body = json.loads(body) if body else {}

            prompt = body.get("prompt", body.get("message", ""))
            session_id = body.get("session_id", "default")

            if not prompt:
                return self._api_response(400, {"error": "Missing prompt"})

            # Get user context from API Gateway
            context = {}
            request_context = event.get("requestContext", {})
            if "authorizer" in request_context:
                claims = request_context["authorizer"].get("claims", {})
                context["user_id"] = claims.get("sub", claims.get("cognito:username"))

            # Process
            result = self.orchestrator.invoke(
                prompt=prompt,
                session_id=session_id,
                context=context,
            )

            return self._api_response(200, result)

        except Exception as e:
            logger.exception("API Gateway handler error")
            return self._api_response(500, {"error": str(e)})

    def _handle_sqs(self, event: Dict[str, Any]) -> Dict[str, Any]:
        """Handle SQS event."""
        results = []

        for record in event.get("Records", []):
            try:
                body = json.loads(record.get("body", "{}"))

                # Check if this is a channel event
                channel_type = body.get("channel_type")
                if channel_type:
                    self.orchestrator.handle_channel_event(
                        event=body.get("event", body),
                        channel_type=channel_type,
                    )
                else:
                    # Direct invocation
                    self.orchestrator.invoke(
                        prompt=body.get("prompt", ""),
                        session_id=body.get("session_id", "default"),
                        context=body.get("context", {}),
                    )

                results.append({"messageId": record.get("messageId"), "status": "success"})

            except Exception as e:
                logger.exception(f"SQS record processing error: {record.get('messageId')}")
                results.append(
                    {
                        "messageId": record.get("messageId"),
                        "status": "error",
                        "error": str(e),
                    }
                )

        return {"batchItemFailures": [r for r in results if r["status"] == "error"]}

    def _handle_eventbridge(self, event: Dict[str, Any]) -> Dict[str, Any]:
        """Handle EventBridge event."""
        try:
            # Route to orchestrator or custom handler
            detail_type = event.get("detail-type", "")

            logger.info(f"EventBridge event: {detail_type}")

            # Default: pass to orchestrator as context
            return {"statusCode": 200, "message": f"Processed {detail_type}"}

        except Exception as e:
            logger.exception("EventBridge handler error")
            return {"statusCode": 500, "error": str(e)}

    def _handle_direct(self, event: Dict[str, Any]) -> Dict[str, Any]:
        """Handle direct Lambda invocation."""
        try:
            result = self.orchestrator.invoke(
                prompt=event.get("prompt", ""),
                session_id=event.get("session_id", "default"),
                context=event.get("context", {}),
            )
            return result
        except Exception as e:
            logger.exception("Direct invocation error")
            return {"error": str(e)}

    def _api_response(
        self,
        status_code: int,
        body: Dict[str, Any],
        headers: Optional[Dict[str, str]] = None,
    ) -> Dict[str, Any]:
        """Create API Gateway response."""
        default_headers = {
            "Content-Type": "application/json",
            "Access-Control-Allow-Origin": "*",
            "Access-Control-Allow-Headers": "Content-Type,Authorization",
            "Access-Control-Allow-Methods": "OPTIONS,POST,GET",
        }

        if headers:
            default_headers.update(headers)

        return {
            "statusCode": status_code,
            "headers": default_headers,
            "body": json.dumps(body),
        }
