"""Card-related API routes""" from typing import List from fastapi import APIRouter, HTTPException, Depends from sqlalchemy.ext.asyncio import AsyncSession from app.models.card import Card, CardDraw, CardDrawResult from app.services.gacha import GachaService from app.repositories.user import UserRepository from app.repositories.card import CardRepository, UniqueCardRepository from app.db.base import get_session router = APIRouter(prefix="/cards", tags=["cards"]) @router.post("/draw", response_model=CardDrawResult) async def draw_card( draw_request: CardDraw, db: AsyncSession = Depends(get_session) ): """ カードを抽選する - **user_did**: ユーザーのatproto DID - **is_paid**: 課金ガチャかどうか """ try: gacha_service = GachaService(db) card, is_unique = await gacha_service.draw_card( user_did=draw_request.user_did, is_paid=draw_request.is_paid ) # 演出タイプを決定 animation_type = "normal" if is_unique: animation_type = "unique" elif card.status.value == "kira": animation_type = "kira" elif card.status.value in ["super_rare", "rare"]: animation_type = "rare" # 新規取得かチェック user_repo = UserRepository(db) card_repo = CardRepository(db) user = await user_repo.get_by_did(draw_request.user_did) count = await card_repo.count_user_cards(user.id, card.id) is_new = count == 1 # 今引いたカードが初めてなら1枚 result = CardDrawResult( card=card, is_new=is_new, animation_type=animation_type ) await db.commit() return result except Exception as e: await db.rollback() raise HTTPException(status_code=500, detail=str(e)) @router.get("/user/{user_did}", response_model=List[Card]) async def get_user_cards( user_did: str, skip: int = 0, limit: int = 100, db: AsyncSession = Depends(get_session) ): """ ユーザーの所有カード一覧を取得 - **user_did**: ユーザーのatproto DID """ user_repo = UserRepository(db) card_repo = CardRepository(db) user = await user_repo.get_by_did(user_did) if not user: raise HTTPException(status_code=404, detail="User not found") user_cards = await card_repo.get_user_cards(user.id, skip=skip, limit=limit) # Convert to API model cards = [] for uc in user_cards: card = Card( id=uc.card_id, cp=uc.cp, status=uc.status, skill=uc.skill, owner_did=user_did, obtained_at=uc.obtained_at, is_unique=uc.is_unique, unique_id=str(uc.unique_id) if uc.unique_id else None ) cards.append(card) return cards @router.get("/unique") async def get_unique_cards(db: AsyncSession = Depends(get_session)): """ 全てのuniqueカード一覧を取得(所有者情報付き) """ unique_repo = UniqueCardRepository(db) unique_cards = await unique_repo.get_all_unique_cards() return [ { "card_id": uc.card_id, "owner_did": uc.owner_did, "obtained_at": uc.obtained_at, "unique_id": str(uc.unique_id) } for uc in unique_cards ] @router.get("/stats") async def get_gacha_stats(db: AsyncSession = Depends(get_session)): """ ガチャ統計情報を取得 """ try: card_repo = CardRepository(db) # 総ガチャ実行数 total_draws = await card_repo.get_total_card_count() # レアリティ別カード数 cards_by_rarity = await card_repo.get_cards_by_rarity() # 成功率計算(簡易版) success_rates = {} if total_draws > 0: for rarity, count in cards_by_rarity.items(): success_rates[rarity] = count / total_draws # 最近の活動(最新10件) recent_cards = await card_repo.get_recent_cards(limit=10) recent_activity = [] for card_data in recent_cards: recent_activity.append({ "timestamp": card_data.get("obtained_at", "").isoformat() if card_data.get("obtained_at") else "", "user_did": card_data.get("owner_did", "unknown"), "card_name": f"Card #{card_data.get('card_id', 0)}", "rarity": card_data.get("status", "common") }) return { "total_draws": total_draws, "cards_by_rarity": cards_by_rarity, "success_rates": success_rates, "recent_activity": recent_activity } except Exception as e: raise HTTPException(status_code=500, detail=f"Statistics error: {str(e)}")