from typing import Any, List, Dict from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from sqlalchemy import func from app import crud, models, schemas from app.api import deps from app.services.bot_simulation import get_bot_simulation_stats router = APIRouter() @router.get("/users", response_model=List[schemas.User]) def read_users( *, db: Session = Depends(deps.get_db), current_user: models.User = Depends(deps.get_current_admin), skip: int = 0, limit: int = 100, ) -> Any: """ Retrieve all users (admin only). """ users = db.query(models.User).offset(skip).limit(limit).all() return users @router.get("/users/{user_id}", response_model=schemas.User) def read_user( *, db: Session = Depends(deps.get_db), current_user: models.User = Depends(deps.get_current_admin), user_id: int, ) -> Any: """ Get a specific user by ID (admin only). """ user = crud.user.get(db, id=user_id) if not user: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="User not found", ) return user @router.put("/users/{user_id}/activate", response_model=schemas.User) def activate_user( *, db: Session = Depends(deps.get_db), current_user: models.User = Depends(deps.get_current_admin), user_id: int, ) -> Any: """ Activate a user (admin only). """ user = crud.user.get(db, id=user_id) if not user: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="User not found", ) if user.is_active: return user updated_user = crud.user.update(db, db_obj=user, obj_in={"is_active": True}) return updated_user @router.put("/users/{user_id}/deactivate", response_model=schemas.User) def deactivate_user( *, db: Session = Depends(deps.get_db), current_user: models.User = Depends(deps.get_current_admin), user_id: int, ) -> Any: """ Deactivate a user (admin only). """ if user_id == current_user.id: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="You cannot deactivate your own account", ) user = crud.user.get(db, id=user_id) if not user: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="User not found", ) if not user.is_active: return user updated_user = crud.user.update(db, db_obj=user, obj_in={"is_active": False}) return updated_user @router.get("/wallets/{user_id}", response_model=List[schemas.Wallet]) def read_user_wallets( *, db: Session = Depends(deps.get_db), current_user: models.User = Depends(deps.get_current_admin), user_id: int, ) -> Any: """ Get a specific user's wallets (admin only). """ user = crud.user.get(db, id=user_id) if not user: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="User not found", ) wallets = crud.wallet.get_by_user(db, user_id=user_id) return wallets @router.put("/wallets/{wallet_id}/adjust", response_model=schemas.Wallet) def adjust_wallet_balance( *, db: Session = Depends(deps.get_db), current_user: models.User = Depends(deps.get_current_admin), wallet_id: int, amount: float, description: str, ) -> Any: """ Adjust a wallet's balance (admin only). """ wallet = crud.wallet.get(db, id=wallet_id) if not wallet: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Wallet not found", ) # Check if adjustment would make balance negative if wallet.balance + amount < 0: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Adjustment would result in negative balance", ) # Update wallet balance updated_wallet = crud.wallet.update_balance( db, wallet_id=wallet_id, amount=abs(amount), add=(amount > 0) ) # Create transaction record crud.transaction.create( db, obj_in=schemas.TransactionCreate( user_id=wallet.user_id, wallet_id=wallet.id, amount=amount, transaction_type=models.TransactionType.ADMIN_ADJUSTMENT, description=f"Admin adjustment: {description}", ), ) return updated_wallet @router.get("/transactions", response_model=List[schemas.Transaction]) def read_all_transactions( *, db: Session = Depends(deps.get_db), current_user: models.User = Depends(deps.get_current_admin), skip: int = 0, limit: int = 100, ) -> Any: """ Retrieve all transactions (admin only). """ transactions = crud.transaction.get_all(db, skip=skip, limit=limit) return transactions @router.get("/statistics", response_model=Dict) def get_statistics( *, db: Session = Depends(deps.get_db), current_user: models.User = Depends(deps.get_current_admin), ) -> Any: """ Get platform statistics (admin only). """ # User statistics total_users = db.query(func.count(models.User.id)).scalar() active_users = db.query(func.count(models.User.id)).filter(models.User.is_active).scalar() verified_users = db.query(func.count(models.User.id)).filter(models.User.is_verified).scalar() kyc_verified_users = db.query(func.count(models.User.id)).filter(models.User.is_kyc_verified).scalar() # Wallet statistics total_spot_balance = db.query(func.sum(models.Wallet.balance)).filter( models.Wallet.wallet_type == models.WalletType.SPOT ).scalar() or 0 total_trading_balance = db.query(func.sum(models.Wallet.balance)).filter( models.Wallet.wallet_type == models.WalletType.TRADING ).scalar() or 0 # Deposit statistics total_deposits = db.query(func.count(models.Deposit.id)).scalar() pending_deposits = db.query(func.count(models.Deposit.id)).filter( models.Deposit.status == models.DepositStatus.PENDING ).scalar() approved_deposits = db.query(func.count(models.Deposit.id)).filter( models.Deposit.status == models.DepositStatus.APPROVED ).scalar() total_deposit_amount = db.query(func.sum(models.Deposit.amount)).filter( models.Deposit.status == models.DepositStatus.APPROVED ).scalar() or 0 # Withdrawal statistics total_withdrawals = db.query(func.count(models.Withdrawal.id)).scalar() pending_withdrawals = db.query(func.count(models.Withdrawal.id)).filter( models.Withdrawal.status == models.WithdrawalStatus.PENDING ).scalar() approved_withdrawals = db.query(func.count(models.Withdrawal.id)).filter( models.Withdrawal.status == models.WithdrawalStatus.APPROVED ).scalar() total_withdrawal_amount = db.query(func.sum(models.Withdrawal.amount)).filter( models.Withdrawal.status == models.WithdrawalStatus.APPROVED ).scalar() or 0 # Bot statistics total_bots = db.query(func.count(models.Bot.id)).scalar() active_bots = db.query(func.count(models.Bot.id)).filter(models.Bot.is_active).scalar() bot_stats = get_bot_simulation_stats(db) # KYC statistics total_kyc = db.query(func.count(models.KYC.id)).scalar() pending_kyc = db.query(func.count(models.KYC.id)).filter( models.KYC.status == models.KYCStatus.PENDING ).scalar() approved_kyc = db.query(func.count(models.KYC.id)).filter( models.KYC.status == models.KYCStatus.APPROVED ).scalar() rejected_kyc = db.query(func.count(models.KYC.id)).filter( models.KYC.status == models.KYCStatus.REJECTED ).scalar() return { "users": { "total": total_users, "active": active_users, "verified": verified_users, "kyc_verified": kyc_verified_users, }, "wallets": { "total_spot_balance": total_spot_balance, "total_trading_balance": total_trading_balance, "total_platform_balance": total_spot_balance + total_trading_balance, }, "deposits": { "total": total_deposits, "pending": pending_deposits, "approved": approved_deposits, "total_amount": total_deposit_amount, }, "withdrawals": { "total": total_withdrawals, "pending": pending_withdrawals, "approved": approved_withdrawals, "total_amount": total_withdrawal_amount, }, "bots": { "total": total_bots, "active": active_bots, **bot_stats, }, "kyc": { "total": total_kyc, "pending": pending_kyc, "approved": approved_kyc, "rejected": rejected_kyc, }, }