"""
Shop API endpoints - catalog, purchases, inventory, cosmetics, consumables
"""
from datetime import datetime
from fastapi import APIRouter, HTTPException
from sqlalchemy import select
from sqlalchemy.orm import selectinload

from app.api.deps import CurrentUser, DbSession, require_participant, require_admin_with_2fa
from app.models import (
    User, Marathon, Participant, Assignment, AssignmentStatus,
    ShopItem, UserInventory, CoinTransaction, ShopItemType,
    CertificationStatus, Challenge, Game,
)
from app.schemas import (
    ShopItemResponse, ShopItemCreate, ShopItemUpdate,
    InventoryItemResponse, PurchaseRequest, PurchaseResponse,
    UseConsumableRequest, UseConsumableResponse,
    EquipItemRequest, EquipItemResponse,
    CoinTransactionResponse, CoinsBalanceResponse, AdminCoinsRequest,
    CertificationRequestSchema, CertificationReviewRequest, CertificationStatusResponse,
    ConsumablesStatusResponse, MessageResponse, SwapCandidate,
    AdminGrantItemRequest,
)
from app.schemas.user import UserPublic
from app.services.shop import shop_service
from app.services.coins import coins_service
from app.services.consumables import consumables_service
from app.services.telegram_notifier import telegram_notifier

router = APIRouter(prefix="/shop", tags=["shop"])


# === Catalog ===

@router.get("/items", response_model=list[ShopItemResponse])
async def get_shop_items(
    current_user: CurrentUser,
    db: DbSession,
    item_type: str | None = None,
    include_unavailable: bool = False,
):
    """Get list of shop items"""
    items = await shop_service.get_available_items(db, item_type, include_unavailable)

    # Get user's inventory to mark owned/equipped items
    user_inventory = await shop_service.get_user_inventory(db, current_user.id)
    owned_ids = {inv.item_id for inv in user_inventory}
    equipped_ids = {inv.item_id for inv in user_inventory if inv.equipped}

    result = []
    for item in items:
        item_dict = ShopItemResponse.model_validate(item).model_dump()
        item_dict["is_owned"] = item.id in owned_ids
        item_dict["is_equipped"] = item.id in equipped_ids
        result.append(ShopItemResponse(**item_dict))

    return result


@router.get("/items/{item_id}", response_model=ShopItemResponse)
async def get_shop_item(
    item_id: int,
    current_user: CurrentUser,
    db: DbSession,
):
    """Get single shop item by ID"""
    item = await shop_service.get_item_by_id(db, item_id)
    if not item:
        raise HTTPException(status_code=404, detail="Item not found")

    is_owned = await shop_service.check_user_owns_item(db, current_user.id, item_id)

    # Check if equipped
    is_equipped = False
    if is_owned:
        inventory = await shop_service.get_user_inventory(db, current_user.id, item.item_type)
        is_equipped = any(inv.equipped and inv.item_id == item_id for inv in inventory)

    response = ShopItemResponse.model_validate(item)
    response.is_owned = is_owned
    response.is_equipped = is_equipped
    return response


# === Purchases ===

@router.post("/purchase", response_model=PurchaseResponse)
async def purchase_item(
    data: PurchaseRequest,
    current_user: CurrentUser,
    db: DbSession,
):
    """Purchase an item from the shop"""
    inv_item, total_cost = await shop_service.purchase_item(
        db, current_user, data.item_id, data.quantity
    )
    await db.commit()
    await db.refresh(current_user)

    item = await shop_service.get_item_by_id(db, data.item_id)

    return PurchaseResponse(
        success=True,
        item=ShopItemResponse.model_validate(item),
        quantity=data.quantity,
        total_cost=total_cost,
        new_balance=current_user.coins_balance,
        message=f"Successfully purchased {item.name} x{data.quantity}",
    )


# === Inventory ===

@router.get("/inventory", response_model=list[InventoryItemResponse])
async def get_my_inventory(
    current_user: CurrentUser,
    db: DbSession,
    item_type: str | None = None,
):
    """Get current user's inventory"""
    inventory = await shop_service.get_user_inventory(db, current_user.id, item_type)
    return [InventoryItemResponse.model_validate(inv) for inv in inventory]


# === Equip/Unequip ===

@router.post("/equip", response_model=EquipItemResponse)
async def equip_item(
    data: EquipItemRequest,
    current_user: CurrentUser,
    db: DbSession,
):
    """Equip a cosmetic item from inventory"""
    item = await shop_service.equip_item(db, current_user, data.inventory_id)
    await db.commit()

    return EquipItemResponse(
        success=True,
        item_type=item.item_type,
        equipped_item=ShopItemResponse.model_validate(item),
        message=f"Equipped {item.name}",
    )


@router.post("/unequip/{item_type}", response_model=EquipItemResponse)
async def unequip_item(
    item_type: str,
    current_user: CurrentUser,
    db: DbSession,
):
    """Unequip item of specified type"""
    valid_types = [ShopItemType.FRAME.value, ShopItemType.TITLE.value,
                   ShopItemType.NAME_COLOR.value, ShopItemType.BACKGROUND.value]
    if item_type not in valid_types:
        raise HTTPException(status_code=400, detail=f"Invalid item type: {item_type}")

    await shop_service.unequip_item(db, current_user, item_type)
    await db.commit()

    return EquipItemResponse(
        success=True,
        item_type=item_type,
        equipped_item=None,
        message=f"Unequipped {item_type}",
    )


# === Consumables ===

@router.post("/use", response_model=UseConsumableResponse)
async def use_consumable(
    data: UseConsumableRequest,
    current_user: CurrentUser,
    db: DbSession,
):
    """Use a consumable item"""
    # Get marathon
    result = await db.execute(select(Marathon).where(Marathon.id == data.marathon_id))
    marathon = result.scalar_one_or_none()
    if not marathon:
        raise HTTPException(status_code=404, detail="Marathon not found")

    # Get participant
    participant = await require_participant(db, current_user.id, data.marathon_id)

    # For some consumables, we need the assignment
    assignment = None
    if data.item_code in ["skip", "skip_exile", "wild_card", "copycat"]:
        if not data.assignment_id:
            raise HTTPException(status_code=400, detail=f"assignment_id is required for {data.item_code}")

        # For copycat and wild_card, we need bonus_assignments to properly handle playthrough
        if data.item_code in ("copycat", "wild_card"):
            result = await db.execute(
                select(Assignment)
                .options(selectinload(Assignment.bonus_assignments))
                .where(
                    Assignment.id == data.assignment_id,
                    Assignment.participant_id == participant.id,
                )
            )
        else:
            result = await db.execute(
                select(Assignment).where(
                    Assignment.id == data.assignment_id,
                    Assignment.participant_id == participant.id,
                )
            )
        assignment = result.scalar_one_or_none()
        if not assignment:
            raise HTTPException(status_code=404, detail="Assignment not found")

    # Use the consumable
    if data.item_code == "skip":
        effect = await consumables_service.use_skip(db, current_user, participant, marathon, assignment)
        effect_description = "Assignment skipped without penalty"
    elif data.item_code == "skip_exile":
        effect = await consumables_service.use_skip_exile(db, current_user, participant, marathon, assignment)
        effect_description = "Assignment skipped, game exiled from pool"
    elif data.item_code == "boost":
        effect = await consumables_service.use_boost(db, current_user, participant, marathon)
        effect_description = f"Boost x{effect['multiplier']} activated for current assignment"
    elif data.item_code == "wild_card":
        if data.game_id is None:
            raise HTTPException(status_code=400, detail="game_id is required for wild_card")
        effect = await consumables_service.use_wild_card(
            db, current_user, participant, marathon, assignment, data.game_id
        )
        effect_description = f"New challenge from {effect['game_name']}: {effect['challenge_title']}"
    elif data.item_code == "lucky_dice":
        effect = await consumables_service.use_lucky_dice(db, current_user, participant, marathon)
        effect_description = f"Lucky Dice rolled: x{effect['multiplier']} multiplier"
    elif data.item_code == "copycat":
        if data.target_participant_id is None:
            raise HTTPException(status_code=400, detail="target_participant_id is required for copycat")
        effect = await consumables_service.use_copycat(
            db, current_user, participant, marathon, assignment, data.target_participant_id
        )
        effect_description = f"Copied challenge: {effect['challenge_title']}"
    elif data.item_code == "undo":
        effect = await consumables_service.use_undo(db, current_user, participant, marathon)
        effect_description = f"Restored {effect['points_restored']} points and streak {effect['streak_restored']}"
    else:
        raise HTTPException(status_code=400, detail=f"Unknown consumable: {data.item_code}")

    await db.commit()

    # Get remaining quantity
    remaining = await consumables_service.get_consumable_count(db, current_user.id, data.item_code)

    return UseConsumableResponse(
        success=True,
        item_code=data.item_code,
        remaining_quantity=remaining,
        effect_description=effect_description,
        effect_data=effect,
    )


@router.get("/consumables/{marathon_id}", response_model=ConsumablesStatusResponse)
async def get_consumables_status(
    marathon_id: int,
    current_user: CurrentUser,
    db: DbSession,
):
    """Get consumables status for participant in marathon"""
    result = await db.execute(select(Marathon).where(Marathon.id == marathon_id))
    marathon = result.scalar_one_or_none()
    if not marathon:
        raise HTTPException(status_code=404, detail="Marathon not found")

    participant = await require_participant(db, current_user.id, marathon_id)

    # Get inventory counts for all consumables
    skips_available = await consumables_service.get_consumable_count(db, current_user.id, "skip")
    skip_exiles_available = await consumables_service.get_consumable_count(db, current_user.id, "skip_exile")
    boosts_available = await consumables_service.get_consumable_count(db, current_user.id, "boost")
    wild_cards_available = await consumables_service.get_consumable_count(db, current_user.id, "wild_card")
    lucky_dice_available = await consumables_service.get_consumable_count(db, current_user.id, "lucky_dice")
    copycats_available = await consumables_service.get_consumable_count(db, current_user.id, "copycat")
    undos_available = await consumables_service.get_consumable_count(db, current_user.id, "undo")

    # Calculate remaining skips for this marathon
    skips_remaining = None
    if marathon.max_skips_per_participant is not None:
        skips_remaining = max(0, marathon.max_skips_per_participant - participant.skips_used)

    return ConsumablesStatusResponse(
        skips_available=skips_available,
        skip_exiles_available=skip_exiles_available,
        skips_used=participant.skips_used,
        skips_remaining=skips_remaining,
        boosts_available=boosts_available,
        has_active_boost=participant.has_active_boost,
        boost_multiplier=consumables_service.BOOST_MULTIPLIER if participant.has_active_boost else None,
        wild_cards_available=wild_cards_available,
        lucky_dice_available=lucky_dice_available,
        has_lucky_dice=participant.has_lucky_dice,
        lucky_dice_multiplier=participant.lucky_dice_multiplier,
        copycats_available=copycats_available,
        undos_available=undos_available,
        can_undo=participant.can_undo,
    )


@router.get("/copycat-candidates/{marathon_id}", response_model=list[SwapCandidate])
async def get_copycat_candidates(
    marathon_id: int,
    current_user: CurrentUser,
    db: DbSession,
):
    """Get participants with active assignments available for copycat (no event required)"""
    result = await db.execute(select(Marathon).where(Marathon.id == marathon_id))
    marathon = result.scalar_one_or_none()
    if not marathon:
        raise HTTPException(status_code=404, detail="Marathon not found")

    participant = await require_participant(db, current_user.id, marathon_id)

    # Get all participants except current user with active assignments
    # Support both challenge assignments and playthrough assignments
    result = await db.execute(
        select(Participant, Assignment, Challenge, Game)
        .join(Assignment, Assignment.participant_id == Participant.id)
        .outerjoin(Challenge, Assignment.challenge_id == Challenge.id)
        .outerjoin(Game, Challenge.game_id == Game.id)
        .options(selectinload(Participant.user))
        .where(
            Participant.marathon_id == marathon_id,
            Participant.id != participant.id,
            Assignment.status == AssignmentStatus.ACTIVE.value,
        )
    )
    rows = result.all()

    candidates = []
    for p, assignment, challenge, game in rows:
        # For playthrough assignments, challenge is None
        if assignment.is_playthrough:
            # Need to get game info for playthrough
            game_result = await db.execute(
                select(Game).where(Game.id == assignment.game_id)
            )
            playthrough_game = game_result.scalar_one_or_none()
            if playthrough_game:
                candidates.append(SwapCandidate(
                    participant_id=p.id,
                    user=UserPublic(
                        id=p.user.id,
                        nickname=p.user.nickname,
                        avatar_url=p.user.avatar_url,
                        role=p.user.role,
                        telegram_avatar_url=p.user.telegram_avatar_url,
                        created_at=p.user.created_at,
                        equipped_frame=None,
                        equipped_title=None,
                        equipped_name_color=None,
                        equipped_background=None,
                    ),
                    challenge_title=f"Прохождение: {playthrough_game.title}",
                    challenge_description=playthrough_game.playthrough_description or "Прохождение игры",
                    challenge_points=playthrough_game.playthrough_points or 0,
                    challenge_difficulty="medium",
                    game_title=playthrough_game.title,
                ))
        elif challenge and game:
            candidates.append(SwapCandidate(
                participant_id=p.id,
                user=UserPublic(
                    id=p.user.id,
                    nickname=p.user.nickname,
                    avatar_url=p.user.avatar_url,
                    role=p.user.role,
                    telegram_avatar_url=p.user.telegram_avatar_url,
                    created_at=p.user.created_at,
                    equipped_frame=None,
                    equipped_title=None,
                    equipped_name_color=None,
                    equipped_background=None,
                ),
                challenge_title=challenge.title,
                challenge_description=challenge.description,
                challenge_points=challenge.points,
                challenge_difficulty=challenge.difficulty,
                game_title=game.title,
            ))

    return candidates


# === Coins ===

@router.get("/balance", response_model=CoinsBalanceResponse)
async def get_coins_balance(
    current_user: CurrentUser,
    db: DbSession,
):
    """Get current user's coins balance with recent transactions"""
    result = await db.execute(
        select(CoinTransaction)
        .where(CoinTransaction.user_id == current_user.id)
        .order_by(CoinTransaction.created_at.desc())
        .limit(10)
    )
    transactions = result.scalars().all()

    return CoinsBalanceResponse(
        balance=current_user.coins_balance,
        recent_transactions=[CoinTransactionResponse.model_validate(t) for t in transactions],
    )


@router.get("/transactions", response_model=list[CoinTransactionResponse])
async def get_coin_transactions(
    current_user: CurrentUser,
    db: DbSession,
    limit: int = 50,
    offset: int = 0,
):
    """Get user's coin transaction history"""
    result = await db.execute(
        select(CoinTransaction)
        .where(CoinTransaction.user_id == current_user.id)
        .order_by(CoinTransaction.created_at.desc())
        .offset(offset)
        .limit(min(limit, 100))
    )
    transactions = result.scalars().all()
    return [CoinTransactionResponse.model_validate(t) for t in transactions]


# === Certification (organizer endpoints) ===

@router.post("/certification/{marathon_id}/request", response_model=CertificationStatusResponse)
async def request_certification(
    marathon_id: int,
    current_user: CurrentUser,
    db: DbSession,
):
    """Request certification for a marathon (organizer only)"""
    # Check user is organizer
    result = await db.execute(
        select(Marathon).where(Marathon.id == marathon_id)
    )
    marathon = result.scalar_one_or_none()
    if not marathon:
        raise HTTPException(status_code=404, detail="Marathon not found")

    if marathon.creator_id != current_user.id and not current_user.is_admin:
        raise HTTPException(status_code=403, detail="Only the creator can request certification")

    if marathon.certification_status != CertificationStatus.NONE.value:
        raise HTTPException(
            status_code=400,
            detail=f"Marathon already has certification status: {marathon.certification_status}"
        )

    marathon.certification_status = CertificationStatus.PENDING.value
    marathon.certification_requested_at = datetime.utcnow()

    await db.commit()
    await db.refresh(marathon)

    return CertificationStatusResponse(
        marathon_id=marathon.id,
        certification_status=marathon.certification_status,
        is_certified=marathon.is_certified,
        certification_requested_at=marathon.certification_requested_at,
        certified_at=marathon.certified_at,
        certified_by_nickname=None,
        rejection_reason=None,
    )


@router.delete("/certification/{marathon_id}/request", response_model=MessageResponse)
async def cancel_certification_request(
    marathon_id: int,
    current_user: CurrentUser,
    db: DbSession,
):
    """Cancel certification request (organizer only)"""
    result = await db.execute(
        select(Marathon).where(Marathon.id == marathon_id)
    )
    marathon = result.scalar_one_or_none()
    if not marathon:
        raise HTTPException(status_code=404, detail="Marathon not found")

    if marathon.creator_id != current_user.id and not current_user.is_admin:
        raise HTTPException(status_code=403, detail="Only the creator can cancel certification request")

    if marathon.certification_status != CertificationStatus.PENDING.value:
        raise HTTPException(status_code=400, detail="No pending certification request to cancel")

    marathon.certification_status = CertificationStatus.NONE.value
    marathon.certification_requested_at = None

    await db.commit()

    return MessageResponse(message="Certification request cancelled")


@router.get("/certification/{marathon_id}", response_model=CertificationStatusResponse)
async def get_certification_status(
    marathon_id: int,
    current_user: CurrentUser,
    db: DbSession,
):
    """Get certification status of a marathon"""
    result = await db.execute(
        select(Marathon)
        .options(selectinload(Marathon.certified_by))
        .where(Marathon.id == marathon_id)
    )
    marathon = result.scalar_one_or_none()
    if not marathon:
        raise HTTPException(status_code=404, detail="Marathon not found")

    return CertificationStatusResponse(
        marathon_id=marathon.id,
        certification_status=marathon.certification_status,
        is_certified=marathon.is_certified,
        certification_requested_at=marathon.certification_requested_at,
        certified_at=marathon.certified_at,
        certified_by_nickname=marathon.certified_by.nickname if marathon.certified_by else None,
        rejection_reason=marathon.certification_rejection_reason,
    )


# === Admin endpoints ===

@router.get("/admin/items", response_model=list[ShopItemResponse])
async def admin_get_all_items(
    current_user: CurrentUser,
    db: DbSession,
):
    """Get all shop items including inactive (admin only)"""
    require_admin_with_2fa(current_user)
    items = await shop_service.get_available_items(db, include_unavailable=True)
    return [ShopItemResponse.model_validate(item) for item in items]


@router.post("/admin/items", response_model=ShopItemResponse)
async def admin_create_item(
    data: ShopItemCreate,
    current_user: CurrentUser,
    db: DbSession,
):
    """Create a new shop item (admin only)"""
    require_admin_with_2fa(current_user)

    # Check code uniqueness
    existing = await shop_service.get_item_by_code(db, data.code)
    if existing:
        raise HTTPException(status_code=400, detail=f"Item with code '{data.code}' already exists")

    item = ShopItem(
        item_type=data.item_type,
        code=data.code,
        name=data.name,
        description=data.description,
        price=data.price,
        rarity=data.rarity,
        asset_data=data.asset_data,
        is_active=data.is_active,
        available_from=data.available_from,
        available_until=data.available_until,
        stock_limit=data.stock_limit,
        stock_remaining=data.stock_limit,  # Initialize remaining = limit
    )
    db.add(item)
    await db.commit()
    await db.refresh(item)

    return ShopItemResponse.model_validate(item)


@router.put("/admin/items/{item_id}", response_model=ShopItemResponse)
async def admin_update_item(
    item_id: int,
    data: ShopItemUpdate,
    current_user: CurrentUser,
    db: DbSession,
):
    """Update a shop item (admin only)"""
    require_admin_with_2fa(current_user)

    item = await shop_service.get_item_by_id(db, item_id)
    if not item:
        raise HTTPException(status_code=404, detail="Item not found")

    # Update fields
    if data.name is not None:
        item.name = data.name
    if data.description is not None:
        item.description = data.description
    if data.price is not None:
        item.price = data.price
    if data.rarity is not None:
        item.rarity = data.rarity
    if data.asset_data is not None:
        item.asset_data = data.asset_data
    if data.is_active is not None:
        item.is_active = data.is_active
    if data.available_from is not None:
        item.available_from = data.available_from
    if data.available_until is not None:
        item.available_until = data.available_until
    if data.stock_limit is not None:
        # If increasing limit, also increase remaining
        if item.stock_limit is not None and data.stock_limit > item.stock_limit:
            diff = data.stock_limit - item.stock_limit
            item.stock_remaining = (item.stock_remaining or 0) + diff
        item.stock_limit = data.stock_limit

    await db.commit()
    await db.refresh(item)

    return ShopItemResponse.model_validate(item)


@router.delete("/admin/items/{item_id}", response_model=MessageResponse)
async def admin_delete_item(
    item_id: int,
    current_user: CurrentUser,
    db: DbSession,
):
    """Delete a shop item (admin only)"""
    require_admin_with_2fa(current_user)

    item = await shop_service.get_item_by_id(db, item_id)
    if not item:
        raise HTTPException(status_code=404, detail="Item not found")

    await db.delete(item)
    await db.commit()

    return MessageResponse(message=f"Item '{item.name}' deleted")


@router.post("/admin/users/{user_id}/coins/grant", response_model=MessageResponse)
async def admin_grant_coins(
    user_id: int,
    data: AdminCoinsRequest,
    current_user: CurrentUser,
    db: DbSession,
):
    """Grant coins to a user (admin only)"""
    require_admin_with_2fa(current_user)

    result = await db.execute(select(User).where(User.id == user_id))
    user = result.scalar_one_or_none()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")

    await coins_service.admin_grant_coins(db, user, data.amount, data.reason, current_user.id)
    await db.commit()

    return MessageResponse(message=f"Granted {data.amount} coins to {user.nickname}")


@router.post("/admin/users/{user_id}/coins/deduct", response_model=MessageResponse)
async def admin_deduct_coins(
    user_id: int,
    data: AdminCoinsRequest,
    current_user: CurrentUser,
    db: DbSession,
):
    """Deduct coins from a user (admin only)"""
    require_admin_with_2fa(current_user)

    result = await db.execute(select(User).where(User.id == user_id))
    user = result.scalar_one_or_none()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")

    success = await coins_service.admin_deduct_coins(db, user, data.amount, data.reason, current_user.id)
    if not success:
        raise HTTPException(status_code=400, detail="User doesn't have enough coins")

    await db.commit()

    return MessageResponse(message=f"Deducted {data.amount} coins from {user.nickname}")


@router.get("/admin/certification/pending", response_model=list[dict])
async def admin_get_pending_certifications(
    current_user: CurrentUser,
    db: DbSession,
):
    """Get list of marathons pending certification (admin only)"""
    require_admin_with_2fa(current_user)

    result = await db.execute(
        select(Marathon)
        .options(selectinload(Marathon.creator))
        .where(Marathon.certification_status == CertificationStatus.PENDING.value)
        .order_by(Marathon.certification_requested_at.asc())
    )
    marathons = result.scalars().all()

    return [
        {
            "id": m.id,
            "title": m.title,
            "creator_nickname": m.creator.nickname,
            "status": m.status,
            "participants_count": len(m.participants) if m.participants else 0,
            "certification_requested_at": m.certification_requested_at,
        }
        for m in marathons
    ]


@router.post("/admin/certification/{marathon_id}/review", response_model=CertificationStatusResponse)
async def admin_review_certification(
    marathon_id: int,
    data: CertificationReviewRequest,
    current_user: CurrentUser,
    db: DbSession,
):
    """Approve or reject marathon certification (admin only)"""
    require_admin_with_2fa(current_user)

    result = await db.execute(
        select(Marathon).where(Marathon.id == marathon_id)
    )
    marathon = result.scalar_one_or_none()
    if not marathon:
        raise HTTPException(status_code=404, detail="Marathon not found")

    if marathon.certification_status != CertificationStatus.PENDING.value:
        raise HTTPException(status_code=400, detail="Marathon is not pending certification")

    if data.approve:
        marathon.certification_status = CertificationStatus.CERTIFIED.value
        marathon.certified_at = datetime.utcnow()
        marathon.certified_by_id = current_user.id
        marathon.certification_rejection_reason = None
    else:
        if not data.rejection_reason:
            raise HTTPException(status_code=400, detail="Rejection reason is required")
        marathon.certification_status = CertificationStatus.REJECTED.value
        marathon.certification_rejection_reason = data.rejection_reason

    await db.commit()
    await db.refresh(marathon)

    return CertificationStatusResponse(
        marathon_id=marathon.id,
        certification_status=marathon.certification_status,
        is_certified=marathon.is_certified,
        certification_requested_at=marathon.certification_requested_at,
        certified_at=marathon.certified_at,
        certified_by_nickname=current_user.nickname if data.approve else None,
        rejection_reason=marathon.certification_rejection_reason,
    )


# === Admin Item Granting ===

@router.post("/admin/users/{user_id}/items/grant", response_model=MessageResponse)
async def admin_grant_item(
    user_id: int,
    data: AdminGrantItemRequest,
    current_user: CurrentUser,
    db: DbSession,
):
    """Grant an item to a user (admin only)"""
    require_admin_with_2fa(current_user)

    # Get target user
    result = await db.execute(select(User).where(User.id == user_id))
    user = result.scalar_one_or_none()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")

    # Get item
    item = await shop_service.get_item_by_id(db, data.item_id)
    if not item:
        raise HTTPException(status_code=404, detail="Item not found")

    # Check if user already has this item in inventory
    result = await db.execute(
        select(UserInventory).where(
            UserInventory.user_id == user_id,
            UserInventory.item_id == data.item_id,
        )
    )
    existing = result.scalar_one_or_none()

    if existing:
        # Add to quantity
        existing.quantity += data.quantity
    else:
        # Create new inventory item
        inventory_item = UserInventory(
            user_id=user_id,
            item_id=data.item_id,
            quantity=data.quantity,
        )
        db.add(inventory_item)

    # Log the action (using coin transaction as audit log)
    transaction = CoinTransaction(
        user_id=user_id,
        amount=0,
        transaction_type="admin_grant_item",
        description=f"Admin granted {item.name} x{data.quantity}: {data.reason}",
        reference_type="admin_action",
        reference_id=current_user.id,
    )
    db.add(transaction)

    await db.commit()

    # Send Telegram notification
    await telegram_notifier.notify_item_granted(
        user=user,
        item_name=item.name,
        quantity=data.quantity,
        reason=data.reason,
        admin_nickname=current_user.nickname,
    )

    return MessageResponse(message=f"Granted {item.name} x{data.quantity} to {user.nickname}")


@router.get("/admin/users/{user_id}/inventory", response_model=list[InventoryItemResponse])
async def admin_get_user_inventory(
    user_id: int,
    current_user: CurrentUser,
    db: DbSession,
    item_type: str | None = None,
):
    """Get a user's inventory (admin only)"""
    require_admin_with_2fa(current_user)

    # Check user exists
    result = await db.execute(select(User).where(User.id == user_id))
    user = result.scalar_one_or_none()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")

    inventory = await shop_service.get_user_inventory(db, user_id, item_type)
    return [InventoryItemResponse.model_validate(inv) for inv in inventory]


@router.delete("/admin/users/{user_id}/inventory/{inventory_id}", response_model=MessageResponse)
async def admin_remove_inventory_item(
    user_id: int,
    inventory_id: int,
    current_user: CurrentUser,
    db: DbSession,
    quantity: int = 1,
):
    """Remove an item from user's inventory (admin only)"""
    require_admin_with_2fa(current_user)

    # Check user exists
    result = await db.execute(select(User).where(User.id == user_id))
    user = result.scalar_one_or_none()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")

    # Get inventory item
    result = await db.execute(
        select(UserInventory)
        .options(selectinload(UserInventory.item))
        .where(
            UserInventory.id == inventory_id,
            UserInventory.user_id == user_id,
        )
    )
    inv = result.scalar_one_or_none()
    if not inv:
        raise HTTPException(status_code=404, detail="Inventory item not found")

    item_name = inv.item.name

    if quantity >= inv.quantity:
        # Remove entirely
        await db.delete(inv)
        removed_qty = inv.quantity
    else:
        # Reduce quantity
        inv.quantity -= quantity
        removed_qty = quantity

    # Log the action
    transaction = CoinTransaction(
        user_id=user_id,
        amount=0,
        transaction_type="admin_remove_item",
        description=f"Admin removed {item_name} x{removed_qty}",
        reference_type="admin_action",
        reference_id=current_user.id,
    )
    db.add(transaction)

    await db.commit()

    return MessageResponse(message=f"Removed {item_name} x{removed_qty} from {user.nickname}")
