"""
Agent Response Contract - API Contract for Agent Execution Responses.

Derived from: definitions/ai/contracts/agent_response.yaml

This module provides typed responses from Django agents back to the Elixir
orchestrator. All agent responses must conform to this schema.

Usage:
    from lightwave.schema.pydantic.contracts.ai import AgentResponse, ResponseStatus

    response = AgentResponse(
        request_id=request.request_id,
        agent_type=request.agent_type,
        status=ResponseStatus.SUCCESS,
        response="Based on your Q4 financials...",
        duration_ms=1523,
    )
"""

from __future__ import annotations

from enum import Enum
from typing import Any
from uuid import UUID

from pydantic import Field, model_validator

from lightwave.schema.pydantic.core.base import LightwaveBaseSchema

from .agent_error import AgentError
from .agent_request import AgentType


class ResponseStatus(str, Enum):
    """Possible outcome statuses for agent execution."""

    SUCCESS = "success"
    ERROR = "error"
    TIMEOUT = "timeout"
    HANDOFF = "handoff"
    PARTIAL = "partial"
    CANCELLED = "cancelled"


class ToolCallStatus(str, Enum):
    """Tool execution status."""

    SUCCESS = "success"
    ERROR = "error"
    SKIPPED = "skipped"


class ToolCallRecord(LightwaveBaseSchema):
    """Record of a tool invocation during agent execution."""

    tool_name: str = Field(
        ...,
        max_length=100,
        description="Name of the tool invoked",
    )

    tool_args: dict[str, Any] | None = Field(
        None,
        description="Arguments passed to the tool",
    )

    status: ToolCallStatus = Field(
        ...,
        description="Tool execution status",
    )

    result: dict[str, Any] | None = Field(
        None,
        description="Tool execution result",
    )

    error: str | None = Field(
        None,
        max_length=1000,
        description="Error message if tool failed",
    )

    duration_ms: int | None = Field(
        None,
        ge=0,
        description="Tool execution time in milliseconds",
    )


class UsageStats(LightwaveBaseSchema):
    """Token usage statistics for the agent execution."""

    input_tokens: int = Field(
        ...,
        ge=0,
        description="Number of input tokens",
    )

    output_tokens: int = Field(
        ...,
        ge=0,
        description="Number of output tokens",
    )

    total_tokens: int = Field(
        ...,
        ge=0,
        description="Total tokens used",
    )

    model: str = Field(
        ...,
        description="Model used for execution",
    )

    estimated_cost_usd: float | None = Field(
        None,
        ge=0,
        description="Estimated cost in USD",
    )


class AgentResponse(LightwaveBaseSchema):
    """
    Response payload from agent execution.

    This is the contract for responses from Django agents back to the
    Elixir orchestrator. The status field determines which other fields
    are required.

    Example:
        # Success response
        response = AgentResponse(
            request_id=request.request_id,
            agent_type=request.agent_type,
            status=ResponseStatus.SUCCESS,
            response="Here is my analysis...",
            tool_calls=[ToolCallRecord(...)],
            usage=UsageStats(...),
            duration_ms=1523,
        )

        # Handoff response
        response = AgentResponse(
            request_id=request.request_id,
            agent_type=AgentType.V_ACCOUNTANT,
            status=ResponseStatus.HANDOFF,
            handoff_to=AgentType.V_LEGAL,
            handoff_reason="Tax implications have legal aspects",
        )

        # Error response
        response = AgentResponse(
            request_id=request.request_id,
            agent_type=request.agent_type,
            status=ResponseStatus.ERROR,
            error=AgentError(code=ErrorCode.TIMEOUT, message="..."),
        )
    """

    request_id: UUID = Field(
        ...,
        description="Request ID from the original AgentRequest",
    )

    agent_type: AgentType = Field(
        ...,
        description="The agent that processed this request",
    )

    status: ResponseStatus = Field(
        ...,
        description="Outcome status of the agent execution",
    )

    response: str | None = Field(
        None,
        max_length=100000,
        description="The agent's text response (null on error)",
    )

    tool_calls: list[ToolCallRecord] | None = Field(
        None,
        description="Tools invoked during execution",
    )

    handoff_to: AgentType | None = Field(
        None,
        description="Agent to hand off to (only if status=handoff)",
    )

    handoff_reason: str | None = Field(
        None,
        max_length=500,
        description="Reason for handoff",
    )

    handoff_context: dict[str, Any] | None = Field(
        None,
        description="Context to pass to the next agent",
    )

    error: AgentError | None = Field(
        None,
        description="Error details (only if status=error)",
    )

    usage: UsageStats | None = Field(
        None,
        description="Token usage statistics",
    )

    duration_ms: int | None = Field(
        None,
        ge=0,
        description="Execution time in milliseconds",
    )

    metadata: dict[str, Any] | None = Field(
        None,
        description="Additional metadata",
    )

    @model_validator(mode="after")
    def validate_status_fields(self) -> "AgentResponse":
        """Validate that required fields are present based on status."""
        if self.status == ResponseStatus.ERROR:
            if self.error is None:
                raise ValueError("error field is required when status is 'error'")

        elif self.status == ResponseStatus.TIMEOUT:
            if self.error is None:
                raise ValueError("error field is required when status is 'timeout'")

        elif self.status == ResponseStatus.HANDOFF:
            if self.handoff_to is None:
                raise ValueError("handoff_to is required when status is 'handoff'")

        elif self.status == ResponseStatus.SUCCESS:
            if self.response is None:
                # Warning level - allow but note it
                pass

        return self

    def is_terminal(self) -> bool:
        """Check if this response represents a terminal state."""
        terminal_statuses = {
            ResponseStatus.SUCCESS,
            ResponseStatus.ERROR,
            ResponseStatus.TIMEOUT,
            ResponseStatus.CANCELLED,
        }
        return self.status in terminal_statuses

    def is_success(self) -> bool:
        """Check if this response represents a successful completion."""
        return self.status == ResponseStatus.SUCCESS

    def needs_handoff(self) -> bool:
        """Check if this response requests a handoff to another agent."""
        return self.status == ResponseStatus.HANDOFF

    def get_http_status(self) -> int:
        """Get appropriate HTTP status code for this response."""
        if self.status == ResponseStatus.SUCCESS:
            return 200
        elif self.status == ResponseStatus.ERROR and self.error:
            return self.error.get_http_status()
        elif self.status == ResponseStatus.TIMEOUT:
            return 504
        elif self.status == ResponseStatus.HANDOFF:
            return 202  # Accepted (processing continues)
        elif self.status == ResponseStatus.PARTIAL:
            return 206  # Partial Content
        elif self.status == ResponseStatus.CANCELLED:
            return 499  # Client Closed Request
        return 200

    @classmethod
    def success(
        cls,
        request_id: UUID,
        agent_type: AgentType,
        response: str,
        tool_calls: list[ToolCallRecord] | None = None,
        usage: UsageStats | None = None,
        duration_ms: int | None = None,
    ) -> "AgentResponse":
        """Create a success response."""
        return cls(
            request_id=request_id,
            agent_type=agent_type,
            status=ResponseStatus.SUCCESS,
            response=response,
            tool_calls=tool_calls,
            usage=usage,
            duration_ms=duration_ms,
        )

    @classmethod
    def create_error(
        cls,
        request_id: UUID,
        agent_type: AgentType,
        error_details: AgentError,
        duration_ms: int | None = None,
    ) -> "AgentResponse":
        """Create an error response."""
        return cls(
            request_id=request_id,
            agent_type=agent_type,
            status=ResponseStatus.ERROR,
            error=error_details,
            duration_ms=duration_ms,
        )

    @classmethod
    def handoff(
        cls,
        request_id: UUID,
        agent_type: AgentType,
        handoff_to: AgentType,
        reason: str,
        context: dict[str, Any] | None = None,
        partial_response: str | None = None,
    ) -> "AgentResponse":
        """Create a handoff response."""
        return cls(
            request_id=request_id,
            agent_type=agent_type,
            status=ResponseStatus.HANDOFF,
            response=partial_response,
            handoff_to=handoff_to,
            handoff_reason=reason,
            handoff_context=context,
        )
