"""Card repository""" from typing import List, Optional from datetime import datetime from sqlalchemy import select, and_, func from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload import uuid from app.repositories.base import BaseRepository from app.db.models import UserCard, UniqueCardRegistry, CardMaster from app.models.card import CardRarity class CardRepository(BaseRepository[UserCard]): """Card repository with custom methods""" def __init__(self, session: AsyncSession): super().__init__(UserCard, session) async def get_user_cards( self, user_id: int, skip: int = 0, limit: int = 100 ) -> List[UserCard]: """Get all cards for a user""" result = await self.session.execute( select(UserCard) .options(selectinload(UserCard.card_info)) .where(UserCard.user_id == user_id) .order_by(UserCard.obtained_at.desc()) .offset(skip) .limit(limit) ) return result.scalars().all() async def count_user_cards(self, user_id: int, card_id: int) -> int: """Count how many of a specific card a user has""" result = await self.session.execute( select(func.count(UserCard.id)) .where( and_( UserCard.user_id == user_id, UserCard.card_id == card_id ) ) ) return result.scalar() or 0 async def create_user_card( self, user_id: int, card_id: int, cp: int, status: CardRarity, skill: Optional[str] = None, is_unique: bool = False ) -> UserCard: """Create a new user card""" unique_id = None if is_unique: unique_id = uuid.uuid4() card = await self.create( user_id=user_id, card_id=card_id, cp=cp, status=status, skill=skill, is_unique=is_unique, unique_id=unique_id ) # If unique, register it globally if is_unique: await self._register_unique_card(card) return card async def _register_unique_card(self, card: UserCard): """Register a unique card in the global registry""" # Get user DID user_did = await self.session.execute( select(User.did).where(User.id == card.user_id) ) user_did = user_did.scalar() registry = UniqueCardRegistry( unique_id=card.unique_id, card_id=card.card_id, owner_did=user_did, obtained_at=card.obtained_at ) self.session.add(registry) async def get_total_card_count(self) -> int: """Get total number of cards obtained""" result = await self.session.execute( select(func.count(UserCard.id)) ) return result.scalar() or 0 async def get_cards_by_rarity(self) -> dict: """Get card count by rarity""" result = await self.session.execute( select(UserCard.status, func.count(UserCard.id)) .group_by(UserCard.status) ) cards_by_rarity = {} for status, count in result.all(): cards_by_rarity[status.value if hasattr(status, 'value') else str(status)] = count return cards_by_rarity async def get_recent_cards(self, limit: int = 10) -> List[dict]: """Get recent card activities""" result = await self.session.execute( select( UserCard.card_id, UserCard.status, UserCard.obtained_at, User.did.label('owner_did') ) .join(User, UserCard.user_id == User.id) .order_by(UserCard.obtained_at.desc()) .limit(limit) ) activities = [] for row in result.all(): activities.append({ 'card_id': row.card_id, 'status': row.status.value if hasattr(row.status, 'value') else str(row.status), 'obtained_at': row.obtained_at, 'owner_did': row.owner_did }) return activities class UniqueCardRepository(BaseRepository[UniqueCardRegistry]): """Unique card registry repository""" def __init__(self, session: AsyncSession): super().__init__(UniqueCardRegistry, session) async def is_card_available(self, card_id: int) -> bool: """Check if a unique card is still available""" result = await self.session.execute( select(func.count(UniqueCardRegistry.id)) .where(UniqueCardRegistry.card_id == card_id) ) count = result.scalar() or 0 return count == 0 async def get_all_unique_cards(self) -> List[UniqueCardRegistry]: """Get all registered unique cards""" result = await self.session.execute( select(UniqueCardRegistry) .order_by(UniqueCardRegistry.obtained_at.desc()) ) return result.scalars().all() async def get_available_unique_cards(self) -> List[int]: """Get list of card IDs that are still available as unique""" # Get all card IDs all_card_ids = set(range(16)) # Get taken card IDs result = await self.session.execute( select(UniqueCardRegistry.card_id).distinct() ) taken_ids = set(result.scalars().all()) # Return available IDs return list(all_card_ids - taken_ids) # Import User model here to avoid circular import from app.db.models import User