"""
User data API endpoints router.

Provides CRUD operations for user sessions, decks, replays,
card collection, groups, networks, preferences, and activity logs.
"""
from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, update, delete
from typing import Optional, List
from datetime import datetime, timezone

from app.core.database import get_db
from app.core.security import get_current_user
from app.models.models import User
from app.models.user_data import (
    UserSession, DeckVersion, GameReplay, ReplayPlayer,
    GameOutcome, UserStatistics, UserCardCollection, CardWishlist,
    UserGroup, GroupMember, GroupChatMessage, UserNetwork,
    NetworkMember, UserPreference, UserActivityLog
)
from app.schemas.user_card_collection import (
    CardCollectionCreate,
    CardCollectionUpdate,
    CardCollectionResponse,
    CardCollectionListResponse,
    WishlistCreate,
    WishlistUpdate,
    WishlistResponse,
    WishlistListResponse,
)
from app.schemas.generic_schemas import MessageResponse, CountResponse, ErrorDetail
from app.schemas.user_data_schemas import (
    SessionCleanupResponse,
    DeckVersionCreate, DeckVersionUpdate, DeckVersionResponse, DeckVersionListResponse,
    GameReplayCreate, GameReplayUpdate, GameReplayResponse, GameReplayListResponse,
    GameOutcomeCreate, GameOutcomeResponse, GameOutcomeListResponse,
    UserStatisticsResponse, StatisticsUpdateResponse,
    GroupCreate, GroupUpdate, GroupResponse, GroupListResponse,
    GroupMemberCreate, GroupMemberUpdate, GroupMemberRemove,
    GroupChatMessageCreate, GroupChatMessageResponse, GroupChatMessageListResponse,
    NetworkCreate, NetworkUpdate, NetworkResponse, NetworkListResponse,
    NetworkMemberCreate,
    UserPreferenceUpdate, UserPreferenceResponse,
    ActivityLogEntry, ActivityLogListResponse,
)

router = APIRouter()


# ===== Session Management =====

@router.get("/sessions/me", response_model=List[SessionCleanupResponse])
async def get_current_sessions(
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Get active sessions for current user."""
    user_id = int(current_user["user_id"])
    
    stmt = (
        select(UserSession)
        .where(
            UserSession.user_id == user_id,
            UserSession.is_active == True,
            UserSession.expires_at > datetime.now(timezone.utc)
        )
    )
    result = await db.execute(stmt)
    sessions = result.scalars().all()
    
    return [
        SessionCleanupResponse(
            cleaned_count=len(sessions),
            message=f"Found {len(sessions)} active sessions"
        )
    ]


@router.delete("/sessions/cleanup", response_model=MessageResponse)
async def cleanup_expired_sessions(
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Cleanup expired sessions for current user."""
    user_id = int(current_user["user_id"])
    
    now = datetime.now(timezone.utc)
    
    stmt = (
        update(UserSession)
        .where(
            UserSession.user_id == user_id,
            UserSession.is_active == True,
            UserSession.expires_at < now
        )
        .values(is_active=False)
    )
    await db.execute(stmt)
    await db.flush()
    
    # Count cleaned sessions
    count_stmt = select(func.count()).select_from(UserSession).where(
        UserSession.user_id == user_id,
        UserSession.is_active == False,
        UserSession.expires_at < now
    )
    count_result = await db.execute(count_stmt)
    cleaned_count = count_result.scalar()
    
    return MessageResponse(message=f"Cleaned {cleaned_count} expired sessions")


@router.post("/sessions/logout", response_model=MessageResponse)
async def logout_current_session(
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Logout current user session."""
    user_id = int(current_user["user_id"])
    
    stmt = (
        update(UserSession)
        .where(
            UserSession.user_id == user_id,
            UserSession.is_active == True
        )
        .values(is_active=False)
    )
    await db.execute(stmt)
    await db.flush()
    
    return MessageResponse(message="Logged out successfully")


# ===== Deck Versions =====

@router.post("/decks/{deck_id}/versions", response_model=DeckVersionResponse, status_code=status.HTTP_201_CREATED)
async def create_deck_version(
    deck_id: int,
    request: DeckVersionCreate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Create a new version of a deck."""
    user_id = int(current_user["user_id"])
    
    # Verify user owns the deck
    deck_check = select(User).where(User.id == user_id)
    deck_result = await db.execute(deck_check)
    user = deck_result.scalar_one_or_none()
    
    if not user:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
    
    # Get current version number
    version_stmt = (
        select(func.max(DeckVersion.version_number))
        .where(DeckVersion.deck_id == deck_id)
    )
    version_result = await db.execute(version_stmt)
    max_version = version_result.scalar() or 0
    
    new_version = DeckVersion(
        deck_id=deck_id,
        version_number=max_version + 1,
        content=request.content,
        status=request.status.value,
        comment=request.comment,
        created_at=datetime.now(timezone.utc)
    )
    
    db.add(new_version)
    await db.flush()
    
    return DeckVersionResponse.model_validate(new_version)


@router.get("/decks/{deck_id}/versions", response_model=DeckVersionListResponse)
async def get_deck_versions(
    deck_id: int,
    page: int = Query(1, ge=1),
    page_size: int = Query(50, ge=1, le=100),
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Get all versions of a deck."""
    offset = (page - 1) * page_size
    
    count_stmt = select(func.count()).select_from(DeckVersion).where(DeckVersion.deck_id == deck_id)
    total_result = await db.execute(count_stmt)
    total = total_result.scalar()
    
    stmt = (
        select(DeckVersion)
        .where(DeckVersion.deck_id == deck_id)
        .order_by(DeckVersion.version_number.desc())
        .offset(offset)
        .limit(page_size)
    )
    result = await db.execute(stmt)
    versions = result.scalars().all()
    
    return DeckVersionListResponse(
        versions=[DeckVersionResponse.model_validate(v) for v in versions],
        total=total,
        page=page,
        page_size=page_size,
        total_pages=(total + page_size - 1) // page_size
    )


@router.patch("/decks/{deck_id}/versions/{version_id}", response_model=DeckVersionResponse)
async def update_deck_version(
    deck_id: int,
    version_id: int,
    request: DeckVersionUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Update a deck version."""
    stmt = select(DeckVersion).where(DeckVersion.id == version_id)
    result = await db.execute(stmt)
    version = result.scalar_one_or_none()
    
    if not version:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Version not found")
    
    update_data = request.model_dump(exclude_unset=True)
    if "status" in update_data:
        update_data["status"] = update_data["status"].value
    
    stmt = (
        update(DeckVersion)
        .where(DeckVersion.id == version_id)
        .values(**update_data)
    )
    await db.execute(stmt)
    await db.flush()
    
    stmt = select(DeckVersion).where(DeckVersion.id == version_id)
    result = await db.execute(stmt)
    updated_version = result.scalar_one_or_none()
    
    return DeckVersionResponse.model_validate(updated_version)


@router.delete("/decks/{deck_id}/versions/{version_id}", response_model=MessageResponse)
async def delete_deck_version(
    deck_id: int,
    version_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Delete a deck version."""
    stmt = select(DeckVersion).where(DeckVersion.id == version_id)
    result = await db.execute(stmt)
    version = result.scalar_one_or_none()
    
    if not version:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Version not found")
    
    stmt = delete(DeckVersion).where(DeckVersion.id == version_id)
    await db.execute(stmt)
    await db.flush()
    
    return MessageResponse(message="Version deleted successfully")


# ===== Game Replays =====

@router.post("/replays", response_model=GameReplayResponse, status_code=status.HTTP_201_CREATED)
async def create_game_replay(
    request: GameReplayCreate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Create a new game replay."""
    # Check if replay already exists
    stmt = select(GameReplay).where(GameReplay.game_uuid == request.game_uuid)
    result = await db.execute(stmt)
    existing = result.scalar_one_or_none()
    
    if existing:
        raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Replay already exists")
    
    replay = GameReplay(
        game_uuid=request.game_uuid,
        room_id=request.room_id,
        game_type=request.game_type,
        format=request.format,
        duration_seconds=request.duration_seconds,
        start_time=request.start_time,
        end_time=request.end_time,
        status=request.status.value,
        replay_data=request.replay_data,
        created_at=datetime.now(timezone.utc),
        updated_at=datetime.now(timezone.utc)
    )
    
    db.add(replay)
    await db.flush()
    
    return GameReplayResponse.model_validate(replay)


@router.get("/replays", response_model=GameReplayListResponse)
async def get_game_replays(
    page: int = Query(1, ge=1),
    page_size: int = Query(50, ge=1, le=100),
    user_id: Optional[int] = None,
    status_filter: Optional[str] = None,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Get game replays with optional filtering."""
    offset = (page - 1) * page_size
    
    # Build WHERE clause
    conditions = []
    if user_id:
        conditions.append(ReplayPlayer.user_id == user_id)
    if status_filter:
        conditions.append(GameReplay.status == status_filter)
    
    # Get total count
    count_stmt = select(func.count()).select_from(GameReplay)
    if conditions:
        count_stmt = count_stmt.join(ReplayPlayer).where(*conditions)
    total_result = await db.execute(count_stmt)
    total = total_result.scalar()
    
    # Get replays
    stmt = select(GameReplay)
    if conditions:
        stmt = stmt.join(ReplayPlayer).where(*conditions)
    stmt = stmt.order_by(GameReplay.start_time.desc()).offset(offset).limit(page_size)
    
    result = await db.execute(stmt)
    replays = result.scalars().all()
    
    return GameReplayListResponse(
        replays=[GameReplayResponse.model_validate(r) for r in replays],
        total=total,
        page=page,
        page_size=page_size,
        total_pages=(total + page_size - 1) // page_size
    )


@router.get("/replays/{replay_id}", response_model=GameReplayResponse)
async def get_game_replay(
    replay_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Get a specific game replay."""
    stmt = select(GameReplay).where(GameReplay.id == replay_id)
    result = await db.execute(stmt)
    replay = result.scalar_one_or_none()
    
    if not replay:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Replay not found")
    
    return GameReplayResponse.model_validate(replay)


@router.patch("/replays/{replay_id}", response_model=GameReplayResponse)
async def update_game_replay(
    replay_id: int,
    request: GameReplayUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Update a game replay."""
    stmt = select(GameReplay).where(GameReplay.id == replay_id)
    result = await db.execute(stmt)
    replay = result.scalar_one_or_none()
    
    if not replay:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Replay not found")
    
    update_data = request.model_dump(exclude_unset=True)
    if "status" in update_data:
        update_data["status"] = update_data["status"].value
    update_data["updated_at"] = datetime.now(timezone.utc)
    
    stmt = (
        update(GameReplay)
        .where(GameReplay.id == replay_id)
        .values(**update_data)
    )
    await db.execute(stmt)
    await db.flush()
    
    stmt = select(GameReplay).where(GameReplay.id == replay_id)
    result = await db.execute(stmt)
    updated_replay = result.scalar_one_or_none()
    
    return GameReplayResponse.model_validate(updated_replay)


@router.delete("/replays/{replay_id}", response_model=MessageResponse)
async def delete_game_replay(
    replay_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Delete a game replay."""
    stmt = select(GameReplay).where(GameReplay.id == replay_id)
    result = await db.execute(stmt)
    replay = result.scalar_one_or_none()
    
    if not replay:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Replay not found")
    
    stmt = delete(GameReplay).where(GameReplay.id == replay_id)
    await db.execute(stmt)
    await db.flush()
    
    return MessageResponse(message="Replay deleted successfully")


# ===== Replay Players =====

@router.post("/replays/{replay_id}/players", status_code=status.HTTP_201_CREATED)
async def add_replay_player(
    replay_id: int,
    user_id: int,
    deck_id: Optional[int] = None,
    position: Optional[int] = None,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Add a player to a game replay."""
    # Verify replay exists
    stmt = select(GameReplay).where(GameReplay.id == replay_id)
    result = await db.execute(stmt)
    replay = result.scalar_one_or_none()
    
    if not replay:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Replay not found")
    
    # Check if player already exists
    player_check = (
        select(ReplayPlayer)
        .where(ReplayPlayer.replay_id == replay_id, ReplayPlayer.user_id == user_id)
    )
    player_result = await db.execute(player_check)
    if player_result.scalar_one_or_none():
        raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Player already in replay")
    
    player = ReplayPlayer(
        replay_id=replay_id,
        user_id=user_id,
        deck_id=deck_id,
        position=position,
        created_at=datetime.now(timezone.utc)
    )
    
    db.add(player)
    await db.flush()
    
    return {"message": "Player added to replay", "player_id": player.id}


@router.get("/replays/{replay_id}/players", response_model=List[dict])
async def get_replay_players(
    replay_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Get all players in a game replay."""
    stmt = select(ReplayPlayer).where(ReplayPlayer.replay_id == replay_id)
    result = await db.execute(stmt)
    players = result.scalars().all()
    
    return [
        {
            "id": p.id,
            "user_id": p.user_id,
            "deck_id": p.deck_id,
            "position": p.position,
            "won": p.won,
            "lost": p.lost,
            "concession": p.concession,
            "turn_one": p.turn_one,
        }
        for p in players
    ]


# ===== Game Outcomes =====

@router.post("/outcomes", response_model=GameOutcomeResponse, status_code=status.HTTP_201_CREATED)
async def create_game_outcome(
    request: GameOutcomeCreate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Create a game outcome record."""
    outcome = GameOutcome(
        user_id=int(current_user["user_id"]),
        game_uuid=request.game_uuid,
        outcome=request.outcome.value,
        opponent_id=request.opponent_id,
        format=request.format,
        rating_before=request.rating_before,
        rating_after=request.rating_after,
        rating_change=request.rating_change,
        created_at=datetime.now(timezone.utc)
    )
    
    db.add(outcome)
    await db.flush()
    
    return GameOutcomeResponse.model_validate(outcome)


@router.get("/outcomes", response_model=GameOutcomeListResponse)
async def get_game_outcomes(
    user_id: Optional[int] = None,
    page: int = Query(1, ge=1),
    page_size: int = Query(50, ge=1, le=100),
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Get game outcomes with optional filtering."""
    offset = (page - 1) * page_size
    
    stmt = select(GameOutcome)
    if user_id:
        stmt = stmt.where(GameOutcome.user_id == user_id)
    stmt = stmt.order_by(GameOutcome.created_at.desc()).offset(offset).limit(page_size)
    
    result = await db.execute(stmt)
    outcomes = result.scalars().all()
    
    count_stmt = select(func.count()).select_from(GameOutcome)
    if user_id:
        count_stmt = count_stmt.where(GameOutcome.user_id == user_id)
    total_result = await db.execute(count_stmt)
    total = total_result.scalar()
    
    return GameOutcomeListResponse(
        outcomes=[GameOutcomeResponse.model_validate(o) for o in outcomes],
        total=total,
        page=page,
        page_size=page_size,
        total_pages=(total + page_size - 1) // page_size
    )


# ===== User Statistics =====

@router.get("/statistics/{user_id}", response_model=UserStatisticsResponse)
async def get_user_statistics(
    user_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Get user game statistics."""
    stmt = select(UserStatistics).where(UserStatistics.user_id == user_id)
    result = await db.execute(stmt)
    stats = result.scalar_one_or_none()
    
    if not stats:
        # Create default statistics
        stats = UserStatistics(
            user_id=user_id,
            total_games=0,
            total_wins=0,
            total_losses=0,
            total_concessions=0,
            win_rate=0.0,
            current_streak=0,
            best_streak=0,
            average_rating=0.0,
            updated_at=datetime.now(timezone.utc)
        )
        db.add(stats)
        await db.flush()
    
    return UserStatisticsResponse.model_validate(stats)


@router.post("/statistics/update", response_model=StatisticsUpdateResponse)
async def update_user_statistics(
    user_id: int,
    outcome: str,  # 'WIN', 'LOSS', 'CONCESSION'
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Update user statistics after a game."""
    stmt = select(UserStatistics).where(UserStatistics.user_id == user_id)
    result = await db.execute(stmt)
    stats = result.scalar_one_or_none()
    
    if not stats:
        stats = UserStatistics(
            user_id=user_id,
            total_games=0,
            total_wins=0,
            total_losses=0,
            total_concessions=0,
            win_rate=0.0,
            current_streak=0,
            best_streak=0,
            average_rating=0.0,
            updated_at=datetime.now(timezone.utc)
        )
        db.add(stats)
    
    # Update statistics
    stats.total_games += 1
    stats.last_game_date = datetime.now(timezone.utc)
    
    if outcome == "WIN":
        stats.total_wins += 1
        stats.current_streak = max(0, stats.current_streak) + 1
        if stats.current_streak > stats.best_streak:
            stats.best_streak = stats.current_streak
    elif outcome in ("LOSS", "CONCESSION"):
        stats.total_losses += 1
        stats.total_concessions += 1 if outcome == "CONCESSION" else 0
        stats.current_streak = 0
    
    # Calculate win rate
    if stats.total_games > 0:
        stats.win_rate = (stats.total_wins / stats.total_games) * 100
    
    stats.updated_at = datetime.now(timezone.utc)
    await db.flush()
    
    return StatisticsUpdateResponse(
        user_id=stats.user_id,
        total_games=stats.total_games,
        total_wins=stats.total_wins,
        total_losses=stats.total_losses,
        win_rate=stats.win_rate,
        current_streak=stats.current_streak,
        updated_at=stats.updated_at
    )


# ===== Card Collection =====

@router.post("/collection", response_model=CardCollectionResponse, status_code=status.HTTP_201_CREATED)
async def add_card_to_collection(
    request: CardCollectionCreate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Add a card to user collection."""
    user_id = int(current_user["user_id"])
    
    # Check if card already exists in collection
    check = (
        select(UserCardCollection)
        .where(
            UserCardCollection.user_id == user_id,
            UserCardCollection.card_id == request.card_id,
            UserCardCollection.is_foil == request.is_foil,
            UserCardCollection.is_alt_art == request.is_alt_art,
        )
    )
    check_result = await db.execute(check)
    existing = check_result.scalar_one_or_none()
    
    if existing:
        # Update quantity
        stmt = (
            update(UserCardCollection)
            .where(UserCardCollection.id == existing.id)
            .values(quantity=existing.quantity + request.quantity)
        )
        await db.execute(stmt)
        await db.flush()
        
        stmt = select(UserCardCollection).where(UserCardCollection.id == existing.id)
        result = await db.execute(stmt)
        updated = result.scalar_one_or_none()
        return CardCollectionResponse.model_validate(updated)
    
    card = UserCardCollection(
        user_id=user_id,
        card_id=request.card_id,
        quantity=request.quantity,
        condition=request.condition,
        language=request.language,
        is_foil=request.is_foil,
        is_alt_art=request.is_alt_art,
        acquired_date=request.acquired_date or datetime.now(timezone.utc),
        acquisition_method=request.acquisition_method,
        notes=request.notes,
        created_at=datetime.now(timezone.utc),
        updated_at=datetime.now(timezone.utc)
    )
    
    db.add(card)
    await db.flush()
    
    return CardCollectionResponse.model_validate(card)


@router.get("/collection", response_model=CardCollectionListResponse)
async def get_user_collection(
    page: int = Query(1, ge=1),
    page_size: int = Query(50, ge=1, le=100),
    is_foil: Optional[bool] = None,
    is_alt_art: Optional[bool] = None,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Get user's card collection."""
    user_id = int(current_user["user_id"])
    offset = (page - 1) * page_size
    
    conditions = [UserCardCollection.user_id == user_id]
    if is_foil is not None:
        conditions.append(UserCardCollection.is_foil == is_foil)
    if is_alt_art is not None:
        conditions.append(UserCardCollection.is_alt_art == is_alt_art)
    
    count_stmt = select(func.count()).select_from(UserCardCollection)
    for cond in conditions:
        count_stmt = count_stmt.where(cond)
    total_result = await db.execute(count_stmt)
    total = total_result.scalar()
    
    stmt = select(UserCardCollection)
    for cond in conditions:
        stmt = stmt.where(cond)
    stmt = stmt.order_by(UserCardCollection.acquired_date.desc()).offset(offset).limit(page_size)
    
    result = await db.execute(stmt)
    cards = result.scalars().all()
    
    return CardCollectionListResponse(
        cards=[CardCollectionResponse.model_validate(c) for c in cards],
        total=total,
        page=page,
        page_size=page_size,
        total_pages=(total + page_size - 1) // page_size
    )


@router.patch("/collection/{card_id}", response_model=CardCollectionResponse)
async def update_card_in_collection(
    card_id: int,
    request: CardCollectionUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Update a card in user collection."""
    user_id = int(current_user["user_id"])
    
    stmt = select(UserCardCollection).where(
        UserCardCollection.id == card_id,
        UserCardCollection.user_id == user_id
    )
    result = await db.execute(stmt)
    card = result.scalar_one_or_none()
    
    if not card:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Card not found in collection")
    
    update_data = request.model_dump(exclude_unset=True)
    update_data["updated_at"] = datetime.now(timezone.utc)
    
    stmt = (
        update(UserCardCollection)
        .where(UserCardCollection.id == card_id)
        .values(**update_data)
    )
    await db.execute(stmt)
    await db.flush()
    
    stmt = select(UserCardCollection).where(UserCardCollection.id == card_id)
    result = await db.execute(stmt)
    updated = result.scalar_one_or_none()
    
    return CardCollectionResponse.model_validate(updated)


@router.delete("/collection/{card_id}", response_model=MessageResponse)
async def remove_card_from_collection(
    card_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Remove a card from user collection."""
    user_id = int(current_user["user_id"])
    
    stmt = select(UserCardCollection).where(
        UserCardCollection.id == card_id,
        UserCardCollection.user_id == user_id
    )
    result = await db.execute(stmt)
    card = result.scalar_one_or_none()
    
    if not card:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Card not found in collection")
    
    stmt = delete(UserCardCollection).where(UserCardCollection.id == card_id)
    await db.execute(stmt)
    await db.flush()
    
    return MessageResponse(message="Card removed from collection")


# ===== Wishlist =====

@router.post("/wishlist", response_model=WishlistResponse, status_code=status.HTTP_201_CREATED)
async def add_to_wishlist(
    request: WishlistCreate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Add a card to wishlist."""
    user_id = int(current_user["user_id"])
    
    # Check if already in wishlist
    check = (
        select(CardWishlist)
        .where(CardWishlist.user_id == user_id, CardWishlist.card_id == request.card_id)
    )
    check_result = await db.execute(check)
    if check_result.scalar_one_or_none():
        raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Card already in wishlist")
    
    item = CardWishlist(
        user_id=user_id,
        card_id=request.card_id,
        max_price=request.max_price,
        notes=request.notes,
        created_at=datetime.now(timezone.utc)
    )
    
    db.add(item)
    await db.flush()
    
    return WishlistResponse.model_validate(item)


@router.get("/wishlist", response_model=WishlistListResponse)
async def get_wishlist(
    page: int = Query(1, ge=1),
    page_size: int = Query(50, ge=1, le=100),
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Get user's wishlist."""
    user_id = int(current_user["user_id"])
    offset = (page - 1) * page_size
    
    count_stmt = select(func.count()).select_from(CardWishlist).where(CardWishlist.user_id == user_id)
    total_result = await db.execute(count_stmt)
    total = total_result.scalar()
    
    stmt = (
        select(CardWishlist)
        .where(CardWishlist.user_id == user_id)
        .order_by(CardWishlist.created_at.desc())
        .offset(offset)
        .limit(page_size)
    )
    result = await db.execute(stmt)
    items = result.scalars().all()
    
    return WishlistListResponse(
        items=[WishlistResponse.model_validate(i) for i in items],
        total=total,
        page=page,
        page_size=page_size,
        total_pages=(total + page_size - 1) // page_size
    )


@router.patch("/wishlist/{item_id}", response_model=WishlistResponse)
async def update_wishlist_item(
    item_id: int,
    request: WishlistUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Update a wishlist item."""
    user_id = int(current_user["user_id"])
    
    stmt = select(CardWishlist).where(
        CardWishlist.id == item_id,
        CardWishlist.user_id == user_id
    )
    result = await db.execute(stmt)
    item = result.scalar_one_or_none()
    
    if not item:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Wishlist item not found")
    
    update_data = request.model_dump(exclude_unset=True)
    
    stmt = (
        update(CardWishlist)
        .where(CardWishlist.id == item_id)
        .values(**update_data)
    )
    await db.execute(stmt)
    await db.flush()
    
    stmt = select(CardWishlist).where(CardWishlist.id == item_id)
    result = await db.execute(stmt)
    updated = result.scalar_one_or_none()
    
    return WishlistResponse.model_validate(updated)


@router.delete("/wishlist/{item_id}", response_model=MessageResponse)
async def remove_from_wishlist(
    item_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Remove a card from wishlist."""
    user_id = int(current_user["user_id"])
    
    stmt = select(CardWishlist).where(
        CardWishlist.id == item_id,
        CardWishlist.user_id == user_id
    )
    result = await db.execute(stmt)
    item = result.scalar_one_or_none()
    
    if not item:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Wishlist item not found")
    
    stmt = delete(CardWishlist).where(CardWishlist.id == item_id)
    await db.execute(stmt)
    await db.flush()
    
    return MessageResponse(message="Removed from wishlist")


# ===== Groups =====

@router.post("/groups", response_model=GroupResponse, status_code=status.HTTP_201_CREATED)
async def create_group(
    request: GroupCreate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Create a new user group."""
    user_id = int(current_user["user_id"])
    
    group = UserGroup(
        name=request.name,
        description=request.description,
        owner_id=user_id,
        is_public=request.is_public,
        max_members=request.max_members,
        created_at=datetime.now(timezone.utc),
        updated_at=datetime.now(timezone.utc)
    )
    
    db.add(group)
    await db.flush()
    
    # Add creator as owner
    member = GroupMember(
        group_id=group.id,
        user_id=user_id,
        role="OWNER",
        joined_at=datetime.now(timezone.utc)
    )
    db.add(member)
    await db.flush()
    
    return GroupResponse.model_validate(group)


@router.get("/groups", response_model=GroupListResponse)
async def get_user_groups(
    page: int = Query(1, ge=1),
    page_size: int = Query(50, ge=1, le=100),
    is_public: Optional[bool] = None,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Get user's groups."""
    user_id = int(current_user["user_id"])
    offset = (page - 1) * page_size
    
    # Get groups where user is member or owner
    member_groups = select(GroupMember.group_id).where(GroupMember.user_id == user_id)
    
    count_stmt = select(func.count()).select_from(UserGroup).where(
        UserGroup.id.in_(member_groups)
    )
    if is_public is not None:
        count_stmt = count_stmt.where(UserGroup.is_public == is_public)
    total_result = await db.execute(count_stmt)
    total = total_result.scalar()
    
    stmt = (
        select(UserGroup)
        .where(UserGroup.id.in_(member_groups))
        .order_by(UserGroup.created_at.desc())
        .offset(offset)
        .limit(page_size)
    )
    result = await db.execute(stmt)
    groups = result.scalars().all()
    
    # Get member counts
    group_ids = [g.id for g in groups]
    member_counts = {}
    if group_ids:
        count_subquery = (
            select(GroupMember.group_id, func.count().label('count'))
            .where(GroupMember.group_id.in_(group_ids))
            .group_by(GroupMember.group_id)
            .subquery()
        )
        count_stmt = select(count_subquery.c.group_id, count_subquery.c.count).where(
            count_subquery.c.group_id.in_(group_ids)
        )
        count_result = await db.execute(count_stmt)
        member_counts = {row[0]: row[1] for row in count_result.fetchall()}
    
    return GroupListResponse(
        groups=[
            GroupResponse(
                **GroupResponse.model_validate(g).model_dump(),
                member_count=member_counts.get(g.id, 0)
            )
            for g in groups
        ],
        total=total,
        page=page,
        page_size=page_size,
        total_pages=(total + page_size - 1) // page_size
    )


@router.get("/groups/{group_id}", response_model=GroupResponse)
async def get_group(
    group_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Get a specific group."""
    stmt = select(UserGroup).where(UserGroup.id == group_id)
    result = await db.execute(stmt)
    group = result.scalar_one_or_none()
    
    if not group:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Group not found")
    
    return GroupResponse.model_validate(group)


@router.patch("/groups/{group_id}", response_model=GroupResponse)
async def update_group(
    group_id: int,
    request: GroupUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Update a group."""
    user_id = int(current_user["user_id"])
    
    # Verify user is owner
    check = (
        select(GroupMember)
        .where(
            GroupMember.group_id == group_id,
            GroupMember.user_id == user_id,
            GroupMember.role == "OWNER"
        )
    )
    check_result = await db.execute(check)
    if not check_result.scalar_one_or_none():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Only group owner can update group")
    
    stmt = select(UserGroup).where(UserGroup.id == group_id)
    result = await db.execute(stmt)
    group = result.scalar_one_or_none()
    
    if not group:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Group not found")
    
    update_data = request.model_dump(exclude_unset=True)
    update_data["updated_at"] = datetime.now(timezone.utc)
    
    stmt = (
        update(UserGroup)
        .where(UserGroup.id == group_id)
        .values(**update_data)
    )
    await db.execute(stmt)
    await db.flush()
    
    stmt = select(UserGroup).where(UserGroup.id == group_id)
    result = await db.execute(stmt)
    updated = result.scalar_one_or_none()
    
    return GroupResponse.model_validate(updated)


@router.delete("/groups/{group_id}", response_model=MessageResponse)
async def delete_group(
    group_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Delete a group."""
    user_id = int(current_user["user_id"])
    
    # Verify user is owner
    check = (
        select(GroupMember)
        .where(
            GroupMember.group_id == group_id,
            GroupMember.user_id == user_id,
            GroupMember.role == "OWNER"
        )
    )
    check_result = await db.execute(check)
    if not check_result.scalar_one_or_none():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Only group owner can delete group")
    
    stmt = delete(UserGroup).where(UserGroup.id == group_id)
    await db.execute(stmt)
    await db.flush()
    
    return MessageResponse(message="Group deleted successfully")


# ===== Group Members =====

@router.post("/groups/{group_id}/members", status_code=status.HTTP_201_CREATED)
async def add_group_member(
    group_id: int,
    request: GroupMemberCreate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Add a member to a group."""
    user_id = int(current_user["user_id"])
    
    # Verify user is admin or owner
    check = (
        select(GroupMember)
        .where(
            GroupMember.group_id == group_id,
            GroupMember.user_id == user_id,
            GroupMember.role.in_(["OWNER", "ADMIN"])
        )
    )
    check_result = await db.execute(check)
    if not check_result.scalar_one_or_none():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Admin privileges required")
    
    # Check if already a member
    member_check = (
        select(GroupMember)
        .where(GroupMember.group_id == group_id, GroupMember.user_id == request.user_id)
    )
    member_result = await db.execute(member_check)
    if member_result.scalar_one_or_none():
        raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Already a member")
    
    member = GroupMember(
        group_id=group_id,
        user_id=request.user_id,
        role=request.role.value,
        joined_at=datetime.now(timezone.utc)
    )
    
    db.add(member)
    await db.flush()
    
    return {"message": "Member added", "member_id": member.id}


@router.patch("/groups/{group_id}/members/{member_id}", response_model=GroupMemberUpdate)
async def update_group_member(
    group_id: int,
    member_id: int,
    request: GroupMemberUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Update a group member's role."""
    user_id = int(current_user["user_id"])
    
    # Verify user is owner
    check = (
        select(GroupMember)
        .where(
            GroupMember.group_id == group_id,
            GroupMember.user_id == user_id,
            GroupMember.role == "OWNER"
        )
    )
    check_result = await db.execute(check)
    if not check_result.scalar_one_or_none():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Only group owner can update roles")
    
    stmt = select(GroupMember).where(GroupMember.id == member_id)
    result = await db.execute(stmt)
    member = result.scalar_one_or_none()
    
    if not member:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Member not found")
    
    stmt = (
        update(GroupMember)
        .where(GroupMember.id == member_id)
        .values(role=request.role.value)
    )
    await db.execute(stmt)
    await db.flush()
    
    return {"message": "Member role updated"}


@router.delete("/groups/{group_id}/members/{member_id}", response_model=MessageResponse)
async def remove_group_member(
    group_id: int,
    member_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Remove a member from a group."""
    user_id = int(current_user["user_id"])
    
    # Verify user is admin or owner
    check = (
        select(GroupMember)
        .where(
            GroupMember.group_id == group_id,
            GroupMember.user_id == user_id,
            GroupMember.role.in_(["OWNER", "ADMIN"])
        )
    )
    check_result = await db.execute(check)
    if not check_result.scalar_one_or_none():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Admin privileges required")
    
    stmt = select(GroupMember).where(GroupMember.id == member_id)
    result = await db.execute(stmt)
    member = result.scalar_one_or_none()
    
    if not member:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Member not found")
    
    stmt = delete(GroupMember).where(GroupMember.id == member_id)
    await db.execute(stmt)
    await db.flush()
    
    return MessageResponse(message="Member removed from group")


# ===== Group Chat Messages =====

@router.post("/groups/{group_id}/messages", response_model=GroupChatMessageResponse, status_code=status.HTTP_201_CREATED)
async def send_group_message(
    group_id: int,
    request: GroupChatMessageCreate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Send a message in a group chat."""
    user_id = int(current_user["user_id"])
    
    # Verify user is a member
    member_check = (
        select(GroupMember)
        .where(GroupMember.group_id == group_id, GroupMember.user_id == user_id)
    )
    member_result = await db.execute(member_check)
    if not member_result.scalar_one_or_none():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Not a group member")
    
    # Verify group exists
    group_check = select(UserGroup).where(UserGroup.id == group_id)
    group_result = await db.execute(group_check)
    if not group_result.scalar_one_or_none():
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Group not found")
    
    message = GroupChatMessage(
        group_id=group_id,
        sender_id=user_id,
        message=request.message,
        created_at=datetime.now(timezone.utc)
    )
    
    db.add(message)
    await db.flush()
    
    # Get sender username
    user_check = select(User).where(User.id == user_id)
    user_result = await db.execute(user_check)
    sender = user_result.scalar_one_or_none()
    
    return GroupChatMessageResponse(
        id=message.id,
        group_id=message.group_id,
        sender_id=message.sender_id,
        sender_username=sender.username if sender else None,
        message=message.message,
        created_at=message.created_at
    )


@router.get("/groups/{group_id}/messages", response_model=GroupChatMessageListResponse)
async def get_group_messages(
    group_id: int,
    page: int = Query(1, ge=1),
    page_size: int = Query(50, ge=1, le=100),
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Get messages in a group chat."""
    offset = (page - 1) * page_size
    
    # Verify user is a member
    member_check = (
        select(GroupMember)
        .where(GroupMember.group_id == group_id, GroupMember.user_id == int(current_user["user_id"]))
    )
    member_result = await db.execute(member_check)
    if not member_result.scalar_one_or_none():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Not a group member")
    
    count_stmt = select(func.count()).select_from(GroupChatMessage).where(GroupChatMessage.group_id == group_id)
    total_result = await db.execute(count_stmt)
    total = total_result.scalar()
    
    stmt = (
        select(GroupChatMessage)
        .where(GroupChatMessage.group_id == group_id)
        .order_by(GroupChatMessage.created_at.desc())
        .offset(offset)
        .limit(page_size)
    )
    result = await db.execute(stmt)
    messages = result.scalars().all()
    
    # Get sender usernames
    sender_ids = [m.sender_id for m in messages]
    sender_names = {}
    if sender_ids:
        user_stmt = select(User.id, User.username).where(User.id.in_(sender_ids))
        user_result = await db.execute(user_stmt)
        sender_names = {row[0]: row[1] for row in user_result.fetchall()}
    
    return GroupChatMessageListResponse(
        messages=[
            GroupChatMessageResponse(
                id=m.id,
                group_id=m.group_id,
                sender_id=m.sender_id,
                sender_username=sender_names.get(m.sender_id),
                message=m.message,
                created_at=m.created_at
            )
            for m in messages
        ],
        total=total,
        page=page,
        page_size=page_size,
        total_pages=(total + page_size - 1) // page_size
    )


# ===== Networks =====

@router.post("/networks", response_model=NetworkResponse, status_code=status.HTTP_201_CREATED)
async def create_network(
    request: NetworkCreate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Create a new user network."""
    user_id = int(current_user["user_id"])
    
    network = UserNetwork(
        name=request.name,
        description=request.description,
        creator_id=user_id,
        is_public=request.is_public,
        created_at=datetime.now(timezone.utc)
    )
    
    db.add(network)
    await db.flush()
    
    # Add creator as owner
    member = NetworkMember(
        network_id=network.id,
        user_id=user_id,
        role="OWNER",
        joined_at=datetime.now(timezone.utc)
    )
    db.add(member)
    await db.flush()
    
    return NetworkResponse.model_validate(network)


@router.get("/networks", response_model=NetworkListResponse)
async def get_user_networks(
    page: int = Query(1, ge=1),
    page_size: int = Query(50, ge=1, le=100),
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Get user's networks."""
    user_id = int(current_user["user_id"])
    offset = (page - 1) * page_size
    
    member_networks = select(NetworkMember.network_id).where(NetworkMember.user_id == user_id)
    
    count_stmt = select(func.count()).select_from(UserNetwork).where(
        UserNetwork.id.in_(member_networks)
    )
    total_result = await db.execute(count_stmt)
    total = total_result.scalar()
    
    stmt = (
        select(UserNetwork)
        .where(UserNetwork.id.in_(member_networks))
        .order_by(UserNetwork.created_at.desc())
        .offset(offset)
        .limit(page_size)
    )
    result = await db.execute(stmt)
    networks = result.scalars().all()
    
    # Get member counts
    network_ids = [n.id for n in networks]
    member_counts = {}
    if network_ids:
        count_subquery = (
            select(NetworkMember.network_id, func.count().label('count'))
            .where(NetworkMember.network_id.in_(network_ids))
            .group_by(NetworkMember.network_id)
            .subquery()
        )
        count_stmt = select(count_subquery.c.network_id, count_subquery.c.count).where(
            count_subquery.c.network_id.in_(network_ids)
        )
        count_result = await db.execute(count_stmt)
        member_counts = {row[0]: row[1] for row in count_result.fetchall()}
    
    return NetworkListResponse(
        networks=[
            NetworkResponse(
                **NetworkResponse.model_validate(n).model_dump(),
                member_count=member_counts.get(n.id, 0)
            )
            for n in networks
        ],
        total=total,
        page=page,
        page_size=page_size,
        total_pages=(total + page_size - 1) // page_size
    )


@router.get("/networks/{network_id}", response_model=NetworkResponse)
async def get_network(
    network_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Get a specific network."""
    stmt = select(UserNetwork).where(UserNetwork.id == network_id)
    result = await db.execute(stmt)
    network = result.scalar_one_or_none()
    
    if not network:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Network not found")
    
    return NetworkResponse.model_validate(network)


@router.patch("/networks/{network_id}", response_model=NetworkResponse)
async def update_network(
    network_id: int,
    request: NetworkUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Update a network."""
    user_id = int(current_user["user_id"])
    
    # Verify user is creator
    check = (
        select(UserNetwork)
        .where(UserNetwork.id == network_id, UserNetwork.creator_id == user_id)
    )
    check_result = await db.execute(check)
    if not check_result.scalar_one_or_none():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Only creator can update network")
    
    stmt = select(UserNetwork).where(UserNetwork.id == network_id)
    result = await db.execute(stmt)
    network = result.scalar_one_or_none()
    
    if not network:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Network not found")
    
    update_data = request.model_dump(exclude_unset=True)
    
    stmt = (
        update(UserNetwork)
        .where(UserNetwork.id == network_id)
        .values(**update_data)
    )
    await db.execute(stmt)
    await db.flush()
    
    stmt = select(UserNetwork).where(UserNetwork.id == network_id)
    result = await db.execute(stmt)
    updated = result.scalar_one_or_none()
    
    return NetworkResponse.model_validate(updated)


@router.delete("/networks/{network_id}", response_model=MessageResponse)
async def delete_network(
    network_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Delete a network."""
    user_id = int(current_user["user_id"])
    
    # Verify user is creator
    check = (
        select(UserNetwork)
        .where(UserNetwork.id == network_id, UserNetwork.creator_id == user_id)
    )
    check_result = await db.execute(check)
    if not check_result.scalar_one_or_none():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Only creator can delete network")
    
    stmt = delete(UserNetwork).where(UserNetwork.id == network_id)
    await db.execute(stmt)
    await db.flush()
    
    return MessageResponse(message="Network deleted successfully")


# ===== Network Members =====

@router.post("/networks/{network_id}/members", status_code=status.HTTP_201_CREATED)
async def add_network_member(
    network_id: int,
    request: NetworkMemberCreate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Add a member to a network."""
    user_id = int(current_user["user_id"])
    
    # Verify user is admin or owner
    check = (
        select(NetworkMember)
        .where(
            NetworkMember.network_id == network_id,
            NetworkMember.user_id == user_id,
            NetworkMember.role.in_(["OWNER", "ADMIN"])
        )
    )
    check_result = await db.execute(check)
    if not check_result.scalar_one_or_none():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Admin privileges required")
    
    # Check if already a member
    member_check = (
        select(NetworkMember)
        .where(NetworkMember.network_id == network_id, NetworkMember.user_id == request.user_id)
    )
    member_result = await db.execute(member_check)
    if member_result.scalar_one_or_none():
        raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Already a member")
    
    member = NetworkMember(
        network_id=network_id,
        user_id=request.user_id,
        role=request.role.value,
        joined_at=datetime.now(timezone.utc)
    )
    
    db.add(member)
    await db.flush()
    
    return {"message": "Member added", "member_id": member.id}


# ===== User Preferences =====

@router.get("/preferences", response_model=UserPreferenceResponse)
async def get_user_preferences(
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Get user preferences."""
    user_id = int(current_user["user_id"])
    
    stmt = select(UserPreference).where(UserPreference.user_id == user_id)
    result = await db.execute(stmt)
    prefs = result.scalar_one_or_none()
    
    if not prefs:
        # Create default preferences
        prefs = UserPreference(
            user_id=user_id,
            theme="light",
            notifications_enabled=True,
            email_notifications=True,
            auto_save_decks=True,
            default_format="standard",
            language="EN",
            updated_at=datetime.now(timezone.utc)
        )
        db.add(prefs)
        await db.flush()
    
    return UserPreferenceResponse.model_validate(prefs)


@router.patch("/preferences", response_model=UserPreferenceResponse)
async def update_user_preferences(
    request: UserPreferenceUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Update user preferences."""
    user_id = int(current_user["user_id"])
    
    stmt = select(UserPreference).where(UserPreference.user_id == user_id)
    result = await db.execute(stmt)
    prefs = result.scalar_one_or_none()
    
    if not prefs:
        # Create default preferences first
        prefs = UserPreference(
            user_id=user_id,
            updated_at=datetime.now(timezone.utc)
        )
        db.add(prefs)
        await db.flush()
    
    update_data = request.model_dump(exclude_unset=True)
    update_data["updated_at"] = datetime.now(timezone.utc)
    
    stmt = (
        update(UserPreference)
        .where(UserPreference.user_id == user_id)
        .values(**update_data)
    )
    await db.execute(stmt)
    await db.flush()
    
    stmt = select(UserPreference).where(UserPreference.user_id == user_id)
    result = await db.execute(stmt)
    updated = result.scalar_one_or_none()
    
    return UserPreferenceResponse.model_validate(updated)


# ===== Activity Log =====

@router.get("/activity", response_model=ActivityLogListResponse)
async def get_activity_log(
    page: int = Query(1, ge=1),
    page_size: int = Query(50, ge=1, le=100),
    activity_type: Optional[str] = None,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Get user activity log."""
    user_id = int(current_user["user_id"])
    offset = (page - 1) * page_size
    
    conditions = [UserActivityLog.user_id == user_id]
    if activity_type:
        conditions.append(UserActivityLog.activity_type == activity_type)
    
    count_stmt = select(func.count()).select_from(UserActivityLog)
    for cond in conditions:
        count_stmt = count_stmt.where(cond)
    total_result = await db.execute(count_stmt)
    total = total_result.scalar()
    
    stmt = select(UserActivityLog)
    for cond in conditions:
        stmt = stmt.where(cond)
    stmt = stmt.order_by(UserActivityLog.created_at.desc()).offset(offset).limit(page_size)
    
    result = await db.execute(stmt)
    entries = result.scalars().all()
    
    return ActivityLogListResponse(
        entries=[ActivityLogEntry.model_validate(e) for e in entries],
        total=total,
        page=page,
        page_size=page_size,
        total_pages=(total + page_size - 1) // page_size
    )
