from beanie import Document
from pydantic import Field
from typing import Optional, Dict, Any
from datetime import datetime, timedelta
from bson import ObjectId

class AuthSession(Document):
    user_id: ObjectId
    session_token: str
    device_info: Optional[Dict[str, Any]] = None
    ip_address: Optional[str] = None
    user_agent: Optional[str] = None
    
    # Session management
    created_at: datetime = Field(default_factory=datetime.utcnow)
    last_accessed: datetime = Field(default_factory=datetime.utcnow)
    expires_at: datetime
    
    # Security
    is_active: bool = True
    revoked_at: Optional[datetime] = None
    revocation_reason: Optional[str] = None
    
    class Settings:
        name = "auth_sessions"
        indexes = [
            "user_id",
            "session_token",
            "expires_at",
            "is_active",
            "created_at"
        ]

    class Config:
        arbitrary_types_allowed = True

    @classmethod
    async def create_session(
        cls,
        user_id: ObjectId,
        session_token: str,
        device_info: Optional[Dict[str, Any]] = None,
        ip_address: Optional[str] = None,
        user_agent: Optional[str] = None,
        expires_in_hours: int = 24
    ) -> "AuthSession":
        """Create a new auth session"""
        expires_at = datetime.utcnow() + timedelta(hours=expires_in_hours)
        
        session = cls(
            user_id=user_id,
            session_token=session_token,
            device_info=device_info,
            ip_address=ip_address,
            user_agent=user_agent,
            expires_at=expires_at
        )
        
        await session.save()
        return session

    def is_expired(self) -> bool:
        """Check if session is expired"""
        return datetime.utcnow() > self.expires_at

    def is_valid(self) -> bool:
        """Check if session is valid (active and not expired)"""
        return self.is_active and not self.is_expired() and self.revoked_at is None

    async def revoke(self, reason: str = "manual_revocation"):
        """Revoke the session"""
        self.is_active = False
        self.revoked_at = datetime.utcnow()
        self.revocation_reason = reason
        await self.save()

    async def extend_session(self, hours: int = 24):
        """Extend session expiration"""
        self.expires_at = datetime.utcnow() + timedelta(hours=hours)
        self.last_accessed = datetime.utcnow()
        await self.save()

    async def update_access(self):
        """Update last accessed time"""
        self.last_accessed = datetime.utcnow()
        await self.save()
