from typing import Optional, Dict, Any, Annotated, List
from pydantic import BaseModel, Field, BeforeValidator, field_validator, ConfigDict
from datetime import datetime
from utils.utils import EventType

StrId = Annotated[str, BeforeValidator(str)]


class AnalyticseventBase(BaseModel):
    event_type: EventType
    session_id: str = Field(..., max_length=255)
    calculation_id: Optional[str] = Field(None, max_length=36)
    event_data: Dict[str, Any] = Field(default_factory=dict)
    user_agent: Optional[str] = None

    @field_validator("session_id")
    @classmethod
    def validate_session_id(cls, v):
        if v is None:
            return v
        v = v.strip()
        if not v:
            raise ValueError("session_id cannot be empty")
        return v

    @field_validator("calculation_id")
    @classmethod
    def validate_calculation_id(cls, v):
        if v is None:
            return v
        v = v.strip()
        if not v:
            raise ValueError("calculation_id cannot be empty when provided")
        return v


class AnalyticseventCreate(AnalyticseventBase):
    pass


class AnalyticseventUpdate(BaseModel):
    event_type: Optional[EventType] = None
    session_id: Optional[str] = Field(None, max_length=255)
    calculation_id: Optional[str] = Field(None, max_length=36)
    event_data: Optional[Dict[str, Any]] = None
    user_agent: Optional[str] = None

    @field_validator("session_id")
    @classmethod
    def validate_session_id(cls, v):
        if v is None:
            return v
        v = v.strip()
        if not v:
            raise ValueError("session_id cannot be empty")
        return v

    @field_validator("calculation_id")
    @classmethod
    def validate_calculation_id(cls, v):
        if v is None:
            return v
        v = v.strip()
        if not v:
            raise ValueError("calculation_id cannot be empty when provided")
        return v


class AnalyticseventResponse(AnalyticseventBase):
    id: StrId
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


class PaginatedAnalyticseventResponse(BaseModel):
    items: List[AnalyticseventResponse]
    total: int
    limit: int
    offset: int

    model_config = ConfigDict(from_attributes=True)