
from datetime import datetime, timedelta, timezone
from sqlalchemy import desc
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
from slowapi.middleware import SlowAPIMiddleware
from services.users import get_user_wallet
from database import get_db
from schemas.transaction import TransactionOut, TransferInitResponse, ValidateTransaction, WalletReloadRequest, WalletTransactionRequest
from utility.auth_token import get_current_user
from core.auth import get_admin_user
from core.excption import NotFoundException
from models.models import Transaction, TransactionStatus, TransactionType, User, Wallet
from services.transactions import rechargement_wallet, transfert_to_client, wallet_transaction, encaissement_safe
from fastapi import APIRouter, Depends, HTTPException, Request, status
from core.config import settings
from sqlalchemy.orm import Session
from sqlalchemy import func
import logging


logger = logging.getLogger(__name__)

# Initialize rate limiter
limiter = Limiter(key_func=get_remote_address)

router = APIRouter()


@router.post('/financials/wallet-paiements/transaction_cinetpay')
@limiter.limit("10/minute")
async def wallet_reload(request:Request, reload_request: WalletReloadRequest,current_user: User = Depends(get_current_user), db: Session = Depends(get_db)):
    try:
        print(f"📱 Recharge demandée: {reload_request.amount} FCFA")
        print(f"👤 Utilisateur: {current_user.username}")
        
        # ✅ Appel avec paramètres nommés (impossible de se tromper)
        result = await wallet_transaction(
            request=request,
            reload_request=reload_request,
            current_user=current_user,
            db=db
        )
        
        print(f"✅ Résultat: {result}")
        return result
        
    except Exception as e:
        print(f"❌ Erreur dans wallet_reload: {str(e)}")
        raise HTTPException(
            status_code=500,
            detail=f"Erreur lors de la recharge: {str(e)}"
        )
        
@router.get("/transaction/{transaction_id}", response_model=TransactionOut)
def get_transaction_by_id(
    transaction_id: str,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    transaction = db.query(Transaction).filter(
        Transaction.id == transaction_id,
        Transaction.user_id == current_user.id
    ).first()
    
    if not transaction:
        raise NotFoundException(detail="Transaction non trouvée")
    return transaction  
        
@router.get("/transaction", response_model=list[TransferInitResponse])
def get_all_transaction(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    transactions = (
        db.query(Transaction)
        .filter(Transaction.user_id == current_user.id)
        .order_by(desc(Transaction.created_at))  # Tri par date décroissante
        .all()
    )
    return transactions

       
@router.get("/wallet")
def get_all_trancation(db: Session = Depends(get_db)):
    transaction = db.query(Wallet).all()

    return transaction


@router.post("/transactions/validate")
async def validate_transaction(
    request: Request,
    validation_request: ValidateTransaction,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    Valide une transaction pending et crédite le portefeuille.
    """

    print(f"🔍 Validation transaction: {validation_request.transaction_id}")

    # 1. Récupérer la transaction
    transaction = db.query(Transaction).filter(
        Transaction.id == validation_request.transaction_id
    ).first()
    if not transaction:
        raise HTTPException(status_code=404, detail="Transaction non trouvée")

    # 2. Vérifier le statut
    if transaction.status != TransactionStatus.PENDING:
        raise HTTPException(
            status_code=400,
            detail=f"Transaction déjà traitée. Statut actuel: {transaction.status.value}"
        )

    # 3. Récupérer l'utilisateur
    user = db.query(User).filter(User.id == transaction.user_id).first()
    if not user:
        raise HTTPException(status_code=404, detail="Utilisateur non trouvé")

    # 4. Récupérer ou créer le portefeuille
    wallet = get_user_wallet(transaction.user_id, db)
    previous_balance = wallet.balance

    # 5. Validation selon type de transaction
    if transaction.transaction_type == TransactionType.RECHARGE_CINETPAY:
        amount_to_credit = transaction.amount

        if wallet.max_balance and (wallet.balance + amount_to_credit) > wallet.max_balance:
            raise HTTPException(
                status_code=400,
                detail=f"Le crédit dépasserait la limite du portefeuille ({wallet.max_balance} FCFA)"
            )

        wallet.balance += amount_to_credit
        print(f"Portefeuille crédité: +{amount_to_credit} FCFA")

    elif transaction.transaction_type == TransactionType.MOBILE_TRANSFER:
        # Pour un transfert sortant, pas de crédit
        print(f"Transfert confirmé: {transaction.amount} FCFA")
        amount_to_credit = 0

    else:
        raise HTTPException(
            status_code=400,
            detail=f"Type de transaction non supporté: {transaction.transaction_type.value}"
        )

    # 6. Mettre à jour la transaction
    transaction.status = TransactionStatus.COMPLETED
    transaction.completed_at = datetime.now(timezone.utc)
   

    # 8. Sauvegarder toutes les modifications
    db.add(transaction)
    db.add(wallet)
    db.commit()
    db.refresh(wallet)

    print(f"Transaction validée: {transaction.id}")
    print(f"Nouveau solde: {wallet.balance} FCFA")

    return transaction

@router.post("/financials/encaissement/nfc")
@limiter.limit("10/minute")
async def encaisemnet_nfc(request: Request,
    validation_request: WalletTransactionRequest,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)):
    body = await request.body()
    print("Body reçu:", body) 
    logger.info(f"Login attempt at {datetime.utcnow().isoformat()} payload {validation_request} from {request.client.host}")
    return await encaissement_safe(validation_request,current_user, db)


@router.post("/financials/rechargement/wallet")
async def rechargement_wallet_user(request: Request,
    validation_request: WalletTransactionRequest,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)):
    body = await request.body()
    print("Body reçu:", body) 
    logger.info(f"Login attempt at {datetime.utcnow().isoformat()} payload {validation_request} from {request.client.host}")
    return await rechargement_wallet(validation_request,current_user, db)


# ==================== Admin Endpoints ====================

@router.get("/admin/transactions", response_model=list[TransferInitResponse])
def get_all_transactions_admin(
    limit: int = 100,
    offset: int = 0,
    status_filter: str = None,
    transaction_type: str = None,
    admin_user: User = Depends(get_admin_user),
    db: Session = Depends(get_db)
):
    """
    [ADMIN] Récupérer toutes les transactions de tous les utilisateurs
    
    **Paramètres :**
    - limit: Nombre maximum de transactions à retourner (défaut: 100)
    - offset: Décalage pour la pagination (défaut: 0)
    - status_filter: Filtrer par statut (pending, completed, failed, cancelled)
    - transaction_type: Filtrer par type de transaction
    
    **Retourne :**
    - Liste de toutes les transactions avec informations utilisateur
    """
    try:
        print(f"🔍 [ADMIN] Récupération des transactions par {admin_user.email}")
        
        # Construire la requête de base
        query = db.query(Transaction).join(User)
        
        # Appliquer les filtres si fournis
        if status_filter:
            try:
                status_enum = TransactionStatus(status_filter)
                query = query.filter(Transaction.status == status_enum)
            except ValueError:
                raise HTTPException(
                    status_code=400, 
                    detail=f"Statut invalide: {status_filter}. Valeurs acceptées: pending, completed, failed, cancelled"
                )
        
        if transaction_type:
            try:
                type_enum = TransactionType(transaction_type)
                query = query.filter(Transaction.transaction_type == type_enum)
            except ValueError:
                raise HTTPException(
                    status_code=400,
                    detail=f"Type de transaction invalide: {transaction_type}"
                )
        
        # Appliquer l'ordre, la pagination et exécuter
        transactions = (
            query
            .order_by(desc(Transaction.created_at))
            .offset(offset)
            .limit(limit)
            .all()
        )
        
        print(f"✅ [ADMIN] {len(transactions)} transactions récupérées")
        
        # Enrichir les données avec les informations utilisateur
        enriched_transactions = []
        for transaction in transactions:
            transaction_data = {
                "id": transaction.id,
                "user_id": transaction.user_id,
                "user_email": transaction.user.email,
                "user_name": transaction.user.full_name or transaction.user.username,
                "transaction_type": transaction.transaction_type.value,
                "amount": transaction.amount,
                "commission_amount": transaction.commission_amount,
                "commission_rate": transaction.commission_rate,
                "status": transaction.status.value,
                "description": transaction.description,
                "reference": transaction.reference,
                "external_reference": transaction.external_reference,
                "payment_method": transaction.payment_method.value if transaction.payment_method else None,
                "merchant_name": transaction.merchant_name,
                "location": transaction.location,
                "created_at": transaction.created_at,
                "completed_at": transaction.completed_at
            }
            enriched_transactions.append(transaction_data)
        
        return enriched_transactions
        
    except HTTPException:
        raise
    except Exception as e:
        print(f"❌ [ADMIN] Erreur récupération transactions: {str(e)}")
        raise HTTPException(
            status_code=500,
            detail=f"Erreur lors de la récupération des transactions: {str(e)}"
        )


@router.get("/admin/transactions/stats")
def get_transactions_stats_admin(
    admin_user: User = Depends(get_admin_user),
    db: Session = Depends(get_db)
):
    """
    [ADMIN] Récupérer les statistiques des transactions
    
    **Retourne :**
    - Nombre total de transactions par statut
    - Montant total des transactions
    - Transactions par type
    - Commissions générées
    """
    try:
        print(f"[ADMIN] Récupération des stats par {admin_user.email}")
        
        # Stats par statut
        stats_by_status = {}
        for status in TransactionStatus:
            count = db.query(Transaction).filter(Transaction.status == status).count()
            stats_by_status[status.value] = count
        
        # Stats par type
        stats_by_type = {}
        for trans_type in TransactionType:
            count = db.query(Transaction).filter(Transaction.transaction_type == trans_type).count()
            stats_by_type[trans_type.value] = count
        
        # Montants totaux
       
        total_amount = db.query(func.sum(Transaction.amount)).filter(
            Transaction.status == TransactionStatus.COMPLETED
        ).scalar() or 0
        
        total_commissions = db.query(func.sum(Transaction.commission_amount)).filter(
            Transaction.status == TransactionStatus.COMPLETED
        ).scalar() or 0
        
        # Transactions récentes (dernières 24h)
        recent_cutoff = datetime.now(timezone.utc) - timedelta(hours=24)
        recent_transactions = db.query(Transaction).filter(
            Transaction.created_at >= recent_cutoff
        ).count()
        
        stats = {
            "total_transactions": db.query(Transaction).count(),
            "stats_by_status": stats_by_status,
            "stats_by_type": stats_by_type,
            "total_amount": total_amount,
            "total_commissions": total_commissions,
            "recent_transactions_24h": recent_transactions,
            "generated_at": datetime.now(timezone.utc).isoformat()
        }
        
        print(f"[ADMIN] Stats générées: {stats['total_transactions']} transactions totales")
        return stats
        
    except Exception as e:
        print(f"[ADMIN] Erreur génération stats: {str(e)}")
        raise HTTPException(
            status_code=500,
            detail=f"Erreur lors de la génération des statistiques: {str(e)}"
        )
@router.get("/transctation/all", response_model=list[TransactionOut])
def get_all_transactions(db: Session = Depends(get_db)):
    """Récupère toutes les transactions."""
    transactions = db.query(Transaction).order_by(Transaction.created_at.desc()).all()
    return transactions

@router.post("/financials/transfert/wallet")
async def transfert_to_user(request: Request,
    validation_request: WalletTransactionRequest,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)):
    body = await request.body()
    print("Body reçu:", body) 
    logger.info(f"Login attempt at {datetime.utcnow().isoformat()} payload {validation_request} from {request.client.host}")
    return await transfert_to_client(validation_request,current_user, db)
