"""Base repository implementation.

This module provides a base repository class with common CRUD operations.
"""

from typing import TypeVar, Generic, Optional, List, Type
from sqlalchemy.orm import Session

from src.infrastructure.database.models.base import BaseModel


ModelType = TypeVar("ModelType", bound=BaseModel)


class BaseRepository(Generic[ModelType]):
    """Base repository with common database operations.
    
    Provides basic CRUD operations that can be inherited by specific repositories.
    
    Attributes:
        model: SQLAlchemy model class
        session: Database session
    """
    
    def __init__(self, model: Type[ModelType], session: Session):
        """Initialize repository.
        
        Args:
            model: SQLAlchemy model class
            session: Database session
        """
        self.model = model
        self._session = session
    
    def get_by_id(self, id: int) -> Optional[ModelType]:
        """Get entity by ID.
        
        Args:
            id: Entity ID
            
        Returns:
            Optional[ModelType]: Entity or None
        """
        return self._session.query(self.model).filter(self.model.id == id).first()
    
    def get_all(self, skip: int = 0, limit: int = 100) -> List[ModelType]:
        """Get all entities with pagination.
        
        Args:
            skip: Number of records to skip
            limit: Maximum number of records to return
            
        Returns:
            List[ModelType]: List of entities
        """
        return self._session.query(self.model).offset(skip).limit(limit).all()
    
    def create(self, entity: ModelType) -> ModelType:
        """Create new entity.
        
        Args:
            entity: Entity to create
            
        Returns:
            ModelType: Created entity
        """
        self._session.add(entity)
        self._session.flush()
        self._session.refresh(entity)
        return entity
    
    def update(self, entity: ModelType) -> ModelType:
        """Update existing entity.
        
        Args:
            entity: Entity to update
            
        Returns:
            ModelType: Updated entity
        """
        self._session.merge(entity)
        self._session.flush()
        self._session.refresh(entity)
        return entity
    
    def delete(self, id: int) -> bool:
        """Delete entity by ID.
        
        Args:
            id: Entity ID
            
        Returns:
            bool: True if deleted, False if not found
        """
        entity = self.get_by_id(id)
        if entity:
            self._session.delete(entity)
            self._session.flush()
            return True
        return False
    
    def count(self) -> int:
        """Count total number of entities.
        
        Returns:
            int: Total count
        """
        return self._session.query(self.model).count()
    
    def exists(self, id: int) -> bool:
        """Check if entity exists.
        
        Args:
            id: Entity ID
            
        Returns:
            bool: True if exists
        """
        return self._session.query(
            self._session.query(self.model).filter(self.model.id == id).exists()
        ).scalar()

