"""Basic operations handler for showcase adapter."""

import time
from typing import Dict, Any
from datetime import datetime, date
from decimal import Decimal
from ..tool import Tool
from snakepit_bridge import telemetry


class BasicOpsHandler:
    """Handler for basic operations like ping, echo, and error demonstrations."""

    def get_tools(self) -> Dict[str, Tool]:
        """Return all tools provided by this handler."""
        return {
            "ping": Tool(self.ping),
            "echo": Tool(self.echo),
            "add": Tool(self.add),
            "error_demo": Tool(self.error_demo),
            "adapter_info": Tool(self.adapter_info),
            "telemetry_demo": Tool(self.telemetry_demo),
            "serialization_demo": Tool(self.serialization_demo),
        }
    
    def ping(self, ctx, message: str = "pong") -> Dict[str, str]:
        """Simple ping operation."""
        return {"message": message, "timestamp": str(time.time())}
    
    def echo(self, ctx, **kwargs) -> Dict[str, Any]:
        """Echo back all provided arguments."""
        return {"echoed": kwargs}
    
    def add(self, ctx, a: float, b: float) -> float:
        """Add two numbers together."""
        return a + b
    
    def error_demo(self, ctx, error_type: str = "generic") -> None:
        """Demonstrate error handling with different error types."""
        if error_type == "value":
            raise ValueError("This is a demonstration ValueError")
        elif error_type == "runtime":
            raise RuntimeError("This is a demonstration RuntimeError")
        else:
            raise Exception("This is a generic exception")
    
    def adapter_info(self, ctx) -> Dict[str, Any]:
        """Return information about the adapter capabilities."""
        return {
            "adapter_name": "ShowcaseAdapter",
            "version": "2.0.0",  # Updated version for refactored adapter
            "capabilities": [
                "binary_serialization",
                "streaming",
                "ml_workflows",
                "session_state_via_elixir"
            ],
            "handlers": [
                "BasicOpsHandler",
                "SessionOpsHandler",
                "BinaryOpsHandler",
                "StreamingOpsHandler",
                "ConcurrentOpsHandler",
                "MLWorkflowHandler"
            ]
        }

    def telemetry_demo(self, ctx, operation: str = "compute", delay_ms: int = 100) -> Dict[str, Any]:
        """
        Demonstrate telemetry emission from Python.

        This tool shows how to use the telemetry API to emit events that are
        captured by Elixir and made available to :telemetry handlers.

        Args:
            ctx: Session context
            operation: Name of the operation to simulate
            delay_ms: How long to simulate work (milliseconds)

        Returns:
            Dict with operation results and telemetry info
        """
        correlation_id = telemetry.get_correlation_id()

        # Example 1: Manual event emission
        telemetry.emit(
            "tool.execution.start",
            {"system_time": time.time_ns()},
            {"tool": "telemetry_demo", "operation": operation},
            correlation_id=correlation_id
        )

        # Example 2: Using span context manager (automatic timing)
        with telemetry.span("tool.execution", {"tool": "telemetry_demo", "operation": operation}, correlation_id):
            # Simulate some work
            time.sleep(delay_ms / 1000.0)

            # Emit a custom metric during the span
            telemetry.emit(
                "tool.result_size",
                {"bytes": 42},
                {"tool": "telemetry_demo"},
                correlation_id=correlation_id
            )

        return {
            "operation": operation,
            "delay_ms": delay_ms,
            "telemetry_enabled": telemetry.is_enabled(),
            "correlation_id": correlation_id,
            "message": "Telemetry events emitted successfully! Check Elixir :telemetry handlers."
        }

    def serialization_demo(self, ctx, demo_type: str = "all") -> Dict[str, Any]:
        """
        Demonstrate graceful serialization of non-JSON objects.

        This tool returns various types that would normally fail JSON serialization:
        - datetime objects (converted via isoformat)
        - Custom classes (converted to marker with type info)
        - Objects with to_dict/model_dump methods (converted automatically)

        Args:
            ctx: Session context
            demo_type: Type of demo - "datetime", "custom", "convertible", or "all"

        Returns:
            Dict containing objects that exercise graceful serialization
        """
        # Custom class without conversion methods
        class CustomResponse:
            def __init__(self, status, data):
                self.status = status
                self.data = data

            def __repr__(self):
                return f"CustomResponse(status={self.status})"

        # Class with to_dict method (like many API response objects)
        class ApiResponse:
            def __init__(self, code, message):
                self.code = code
                self.message = message

            def to_dict(self):
                return {"code": self.code, "message": self.message}

        # Class with model_dump method (Pydantic v2 style)
        class PydanticLike:
            def __init__(self, field1, field2):
                self.field1 = field1
                self.field2 = field2

            def model_dump(self):
                return {"field1": self.field1, "field2": self.field2}

        result = {"demo_type": demo_type, "description": "Graceful serialization demo"}

        if demo_type in ("datetime", "all"):
            result["datetime_demo"] = {
                "datetime_now": datetime.now(),
                "date_today": date.today(),
                "preserved_string": "This stays as-is",
                "preserved_number": 42,
            }

        if demo_type in ("custom", "all"):
            result["custom_class_demo"] = {
                "custom_object": CustomResponse(200, "success"),
                "preserved_string": "This is preserved",
                "nested": {
                    "another_custom": CustomResponse(404, "not found"),
                    "normal_value": 123,
                },
            }

        if demo_type in ("convertible", "all"):
            result["convertible_demo"] = {
                "api_response": ApiResponse(200, "OK"),
                "pydantic_like": PydanticLike("value1", "value2"),
            }

        if demo_type in ("mixed_list", "all"):
            result["mixed_list_demo"] = [
                1,
                "two",
                datetime.now(),
                CustomResponse(500, "error"),
                {"nested": "dict"},
                ApiResponse(201, "Created"),
            ]

        if demo_type in ("complex", "all"):
            result["complex_demo"] = self._build_complex_demo()

        return result

    def _build_complex_demo(self) -> Dict[str, Any]:
        """
        Build a complex demo showing nested structures with various conversion patterns.

        Demonstrates:
        - Objects with model_dump() -> converted to dict
        - Objects with to_dict() -> converted to dict
        - Objects without conversion methods -> become markers
        - Nested structures mixing serializable and non-serializable
        - Secret redaction in repr (when enabled)
        """
        import uuid

        # Object with model_dump() method - converts automatically
        class ServiceResponse:
            def __init__(self, data, metadata):
                self.id = f"resp-{uuid.uuid4().hex[:8]}"
                self.data = data
                self.metadata = metadata
                self.created = datetime.now()

            def model_dump(self):
                return {
                    "id": self.id,
                    "data": self.data,
                    "metadata": self.metadata,
                    "created": self.created.isoformat(),
                }

        # Object with to_dict() method - converts automatically
        class QueryResult:
            def __init__(self, value, score=None):
                self.value = value
                self.score = score
                self._internal = []  # Internal state not exposed

            def to_dict(self):
                return {
                    "value": self.value,
                    "score": self.score,
                }

        # Object WITHOUT conversion methods - becomes marker
        class InternalClient:
            def __init__(self, endpoint):
                self.endpoint = endpoint
                self._api_key = "sk-secret-key-12345"  # Has secret

            def __repr__(self):
                # Real repr might accidentally expose secrets
                return f"InternalClient(endpoint={self.endpoint}, api_key={self._api_key})"

        # Another object without conversion - becomes marker
        class RequestLog:
            def __init__(self, request_id, payload, response_obj):
                self.request_id = request_id
                self.payload = payload
                self.response = response_obj  # Nested non-serializable
                self.timestamp = datetime.now()

            # No conversion method

        # Build nested structure
        client = InternalClient("https://api.example.com")

        logs = [
            RequestLog(
                request_id="req-001",
                payload={"query": "test"},
                response_obj=ServiceResponse(
                    data={"result": "success"},
                    metadata={"latency_ms": 245}
                )
            ),
            RequestLog(
                request_id="req-002",
                payload={"query": "another"},
                response_obj=ServiceResponse(
                    data={"result": "partial"},
                    metadata={"latency_ms": 1820}
                )
            ),
        ]

        result = QueryResult(value="computed result", score=0.95)

        return {
            "description": "Complex nested structure with mixed serialization",
            "client": client,  # Marker (with redacted secret if repr enabled)
            "result": result,  # Converts via to_dict()
            "logs": logs,  # List of RequestLog markers
            "summary": {
                "total_requests": len(logs),
                "request_ids": [log.request_id for log in logs],
            },
            "latest_response": ServiceResponse(  # Converts via model_dump()
                data={"final": "output"},
                metadata={"processed": True}
            ),
        }
