# services/suppliers/app/repositories/base.py
"""
Base repository class for common database operations
"""

from typing import TypeVar, Generic, List, Optional, Dict, Any
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import desc, asc, select, func
from uuid import UUID

T = TypeVar('T')


class BaseRepository(Generic[T]):
    """Base repository with common CRUD operations"""
    
    def __init__(self, model: type, db: AsyncSession):
        self.model = model
        self.db = db
    
    async def create(self, obj_data: Dict[str, Any]) -> T:
        """Create a new record"""
        db_obj = self.model(**obj_data)
        self.db.add(db_obj)
        await self.db.commit()
        await self.db.refresh(db_obj)
        return db_obj
    
    async def get_by_id(self, record_id: UUID) -> Optional[T]:
        """Get record by ID"""
        stmt = select(self.model).filter(self.model.id == record_id)
        result = await self.db.execute(stmt)
        return result.scalar_one_or_none()
    
    async def get_by_tenant_id(self, tenant_id: UUID, limit: int = 100, offset: int = 0) -> List[T]:
        """Get records by tenant ID with pagination"""
        stmt = select(self.model).filter(
            self.model.tenant_id == tenant_id
        ).limit(limit).offset(offset)
        result = await self.db.execute(stmt)
        return result.scalars().all()
    
    async def update(self, record_id: UUID, update_data: Dict[str, Any]) -> Optional[T]:
        """Update record by ID"""
        db_obj = await self.get_by_id(record_id)
        if db_obj:
            for key, value in update_data.items():
                if hasattr(db_obj, key):
                    setattr(db_obj, key, value)
            await self.db.commit()
            await self.db.refresh(db_obj)
        return db_obj
    
    async def delete(self, record_id: UUID) -> bool:
        """Delete record by ID"""
        db_obj = await self.get_by_id(record_id)
        if db_obj:
            await self.db.delete(db_obj)
            await self.db.commit()
            return True
        return False
    
    async def count_by_tenant(self, tenant_id: UUID) -> int:
        """Count records by tenant"""
        stmt = select(func.count()).select_from(self.model).filter(
            self.model.tenant_id == tenant_id
        )
        result = await self.db.execute(stmt)
        return result.scalar() or 0
    
    def list_with_filters(
        self,
        tenant_id: UUID,
        filters: Optional[Dict[str, Any]] = None,
        sort_by: str = "created_at",
        sort_order: str = "desc",
        limit: int = 100,
        offset: int = 0
    ) -> List[T]:
        """List records with filtering and sorting"""
        query = self.db.query(self.model).filter(self.model.tenant_id == tenant_id)
        
        # Apply filters
        if filters:
            for key, value in filters.items():
                if hasattr(self.model, key) and value is not None:
                    query = query.filter(getattr(self.model, key) == value)
        
        # Apply sorting
        if hasattr(self.model, sort_by):
            if sort_order.lower() == "desc":
                query = query.order_by(desc(getattr(self.model, sort_by)))
            else:
                query = query.order_by(asc(getattr(self.model, sort_by)))
        
        return query.limit(limit).offset(offset).all()
    
    def exists(self, record_id: UUID) -> bool:
        """Check if record exists"""
        return self.db.query(self.model).filter(self.model.id == record_id).first() is not None