"""Data models for FastAPI Monitor."""

from datetime import datetime
from typing import Dict, List, Optional

from pydantic import BaseModel, Field, field_validator


class RequestData(BaseModel):
    """Request data model."""

    method: str = Field(..., description="HTTP method")
    path: str = Field(..., description="Request path")
    query_params: Optional[str] = Field(None, description="Query parameters")
    headers: Dict[str, str] = Field(default_factory=dict, description="Request headers")
    client_ip: Optional[str] = Field(None, description="Client IP address")
    user_agent: Optional[str] = Field(None, description="User agent")
    request_body: Optional[str] = Field(None, description="Request body")
    request_size: int = Field(default=0, ge=0, description="Request size in bytes")
    timestamp: float = Field(..., description="Request timestamp")

    @field_validator("method")
    @classmethod
    def validate_method(cls, v: str) -> str:
        """Validate HTTP method."""
        allowed_methods = {"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"}
        if v.upper() not in allowed_methods:
            raise ValueError(f"Invalid HTTP method: {v}")
        return v.upper()

    @field_validator("path")
    @classmethod
    def validate_path(cls, v: str) -> str:
        """Validate request path."""
        if not v.startswith("/"):
            v = "/" + v
        return v


class ResponseData(BaseModel):
    """Response data model."""

    status_code: int = Field(..., ge=100, le=599, description="HTTP status code")
    response_time: float = Field(..., ge=0, description="Response time in milliseconds")
    response_size: int = Field(default=0, ge=0, description="Response size in bytes")
    response_headers: Dict[str, str] = Field(default_factory=dict, description="Response headers")
    response_body: Optional[str] = Field(None, description="Response body")


class ErrorInfo(BaseModel):
    """Error information model."""

    error_type: str = Field(..., description="Error type/class name")
    error_message: str = Field(..., description="Error message")
    traceback: Optional[str] = Field(None, description="Error traceback")


class MonitorRecord(BaseModel):
    """Complete monitoring record."""

    id: Optional[int] = Field(None, description="Record ID")
    request: RequestData
    response: ResponseData
    error_info: Optional[ErrorInfo] = Field(None, description="Error information if any")
    created_at: Optional[datetime] = Field(None, description="Record creation time")

    @property
    def formatted_time(self) -> str:
        """Get formatted timestamp."""
        dt = datetime.fromtimestamp(self.request.timestamp)
        return dt.strftime("%I:%M:%S %p")

    @property
    def is_error(self) -> bool:
        """Check if this record represents an error."""
        return self.error_info is not None or self.response.status_code >= 400


class StatsData(BaseModel):
    """Statistics data model."""

    total_requests: int = Field(default=0, ge=0, description="Total number of requests")
    avg_response_time: float = Field(default=0.0, ge=0, description="Average response time")
    error_count: int = Field(default=0, ge=0, description="Number of errors")
    status_codes: Dict[str, int] = Field(default_factory=dict, description="Status code distribution")

    @property
    def error_rate(self) -> float:
        """Calculate error rate percentage."""
        if self.total_requests == 0:
            return 0.0
        return (self.error_count / self.total_requests) * 100


class TimeSeriesPoint(BaseModel):
    """Time series data point."""

    time: str = Field(..., description="Time label")
    count: int = Field(default=0, ge=0, description="Request count")


class ResponseTimeDistribution(BaseModel):
    """Response time distribution data."""

    range: str = Field(..., description="Time range label")
    count: int = Field(default=0, ge=0, description="Count in this range")


class EndpointStats(BaseModel):
    """Endpoint statistics."""

    path: str = Field(..., description="Endpoint path")
    count: int = Field(default=0, ge=0, description="Request count")
    avg_time: float = Field(default=0.0, ge=0, description="Average response time")


class StatusTrend(BaseModel):
    """Status code trend data."""

    date: str = Field(..., description="Date")
    status_code: int = Field(..., ge=100, le=599, description="HTTP status code")
    count: int = Field(default=0, ge=0, description="Count")


class AnalyticsData(BaseModel):
    """Analytics dashboard data."""

    requests_over_time: List[TimeSeriesPoint] = Field(default_factory=list)
    resolution: str = Field(default="30s", description="Time resolution")
    response_time_distribution: List[ResponseTimeDistribution] = Field(default_factory=list)
    top_endpoints: List[EndpointStats] = Field(default_factory=list)
    status_trends: List[StatusTrend] = Field(default_factory=list)


class PaginationInfo(BaseModel):
    """Pagination information."""

    current_page: int = Field(default=1, ge=1, description="Current page number")
    total_pages: int = Field(default=1, ge=1, description="Total number of pages")
    total_records: int = Field(default=0, ge=0, description="Total number of records")
    page_size: int = Field(default=20, ge=1, le=100, description="Number of records per page")

    @property
    def has_next(self) -> bool:
        """Check if there's a next page."""
        return self.current_page < self.total_pages

    @property
    def has_previous(self) -> bool:
        """Check if there's a previous page."""
        return self.current_page > 1
