from datetime import datetime, timezone
from typing import Annotated, Dict, Optional

from pydantic import BaseModel, BeforeValidator, ConfigDict, Field

# Convert MongoDB ObjectId to string for GraphQL compatibility
PyObjectId = Annotated[str, BeforeValidator(str)]


class BaseDBModel(BaseModel):
    """
    Base model for all MongoDB documents with built-in audit fields.
    Uses _id alias for MongoDB compatibility.
    """

    id: Optional[PyObjectId] = Field(alias="_id", default=None)

    created_at: Optional[datetime] = Field(
        default_factory=lambda: datetime.now(timezone.utc)
    )
    updated_at: Optional[datetime] = Field(
        default_factory=lambda: datetime.now(timezone.utc)
    )
    deleted_at: Optional[datetime] = Field(default=None)

    created_by: str = Field(default="system")
    updated_by: str = Field(default="system")

    model_config = ConfigDict(
        populate_by_name=True,
        arbitrary_types_allowed=True,
    )


class TimeSeriesDBModel(BaseModel):
    """
    Base model for MongoDB Time Series collections.

    Time Series collections are optimized for time-stamped data like:
    - Sensor readings
    - Logs
    - Metrics
    - Events

    Required fields:
    - time_field: The timestamp field (default: 'timestamp')
    - meta_field: Optional metadata field for grouping

    Usage:
        class SensorReading(TimeSeriesDBModel):
            timestamp: datetime  # Required time field
            sensor_id: str       # Metadata field
            temperature: float
            humidity: float

            class TimeSeriesConfig:
                time_field = "timestamp"
                meta_field = "sensor_id"
                granularity = "seconds"  # or "minutes", "hours"
    """

    id: Optional[PyObjectId] = Field(alias="_id", default=None)

    class TimeSeriesConfig:
        """Configuration for Time Series collection."""

        time_field: str = "timestamp"
        meta_field: Optional[str] = None
        granularity: str = "seconds"  # "seconds", "minutes", or "hours"

    model_config = ConfigDict(
        populate_by_name=True,
        arbitrary_types_allowed=True,
    )


class AuditLogModel(BaseModel):
    """Model for audit log entries stored in Time Series collection."""

    id: Optional[PyObjectId] = Field(alias="_id", default=None)
    date: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
    user: str
    action: str  # "CREATE", "UPDATE", "DELETE"
    collection: str
    doc_id: str
    changes: Optional[Dict] = None

    model_config = ConfigDict(
        populate_by_name=True,
        arbitrary_types_allowed=True,
    )
