import logging
import uuid
from fastapi import Depends, HTTPException, Request


from utility.stock import get_admin_stock
from services.users import get_user_wallet
from schemas.transaction import WalletReloadRequest, WalletTransactionRequest, WalletTransferRequest
from sqlalchemy.orm import Session
from core.excption import NotFoundException
from models.models import Notification, NotificationPriority, PaymentMethod, Transaction, TransactionStatus, TransactionType, User
from utility.transactions import cinetpay_service 
from datetime import datetime 
from core.config import settings
# Récupérer les taux de commission depuis la base de données
from services.commission_service import CommissionService
from services.loan_auto_repayment import LoanAutoRepaymentService
logger = logging.getLogger(__name__)
from utility.payment_api import InitPaymentWeb, PaymentResponse
from core.config import settings

async def wallet_transaction(
    request: Request,
    reload_request: WalletReloadRequest,
    current_user: User,  # ✅ User complet injecté par get_current_user()
    db: Session
):
    """
    Création d'une transaction wallet + génération du lien de paiement CinetPay

    FLUX COMPLET:
    1. Vérifier si l'utilisateur a un prêt actif
    2. Calculer les commissions TIM CASH
    3. Créer la transaction de recharge
    4. Générer le lien de paiement CinetPay
    5. Lors du callback de paiement réussi, le remboursement automatique sera appliqué
    """
    try:
        

        # 1. Vérifier si l'utilisateur a un prêt actif
        active_loan = LoanAutoRepaymentService.get_active_loan(current_user.id, db)

        if active_loan:
            total_due = LoanAutoRepaymentService.calculate_total_due(active_loan)
            print(f"⚠️  Prêt actif détecté:")
            print(f"   • Prêt ID: {active_loan.id}")
            print(f"   • Montant dû: {total_due} FCFA")
            print(f"   • Date d'échéance: {active_loan.due_date}")


        # 2. Récupérer les taux de commission configurables
        commission_rates = CommissionService.get_recharge_commission_rates(db)

        # 3. Calculer les montants avec les taux configurables
        recharge_amount = reload_request.amount  # Montant que le client veut recevoir
        commission_calculation = CommissionService.calculate_commissions(recharge_amount, commission_rates)

        # Extraire les montants calculés
        net_amount = commission_calculation["net_amount"]  # Montant crédité au client
        timcash_commission = commission_calculation["timcash_commission"]  # Commission TIM CASH
        amount_to_cinetpay = commission_calculation["amount_to_cinetpay"]  # Montant envoyé à CinetPay
        total_payment = commission_calculation["total_payment"]  # Montant total payé par le client

        print(f"💰 Calcul recharge:")
        print(f"   • Montant demandé: {recharge_amount} FCFA")
        print(f"   • Commission TIM CASH ({commission_rates.get('timcash_rate', 0.02)*100}%): {timcash_commission} FCFA")
        print(f"   • Montant envoyé à CinetPay: {amount_to_cinetpay} FCFA")
        print(f"   • Total payé par client: {total_payment} FCFA")
        print(f"   • CinetPay déduira automatiquement ~{commission_rates.get('cinetpay_rate', 0.01)*100}%")

        # Créer une transaction en statut PENDING
        transaction = Transaction(
            id=str(uuid.uuid4()),
            user_id=current_user.id,
            transaction_type=TransactionType.RECHARGE_CINETPAY,
            amount=reload_request.amount,  # Montant qui sera crédité sur le wallet
            commission_amount=timcash_commission,  # Commission TIM CASH uniquement
            commission_rate=commission_rates.get('timcash_rate', 0.02),
            status=TransactionStatus.PENDING,
            description=f"Recharge CinetPay - {reload_request.amount} FCFA (Frais: {timcash_commission} FCFA)",
            reference=f"RELOAD-{str(uuid.uuid4())[:10]}",
            payment_method=PaymentMethod.MOBILE_MONEY
        )
        
        db.add(transaction)
        db.commit()
        db.refresh(transaction)

        # Préparer données pour CinetPay
        # IMPORTANT: On envoie le montant AVEC la commission TIM CASH
        # CinetPay déduira automatiquement SA commission via leur API
        print(transaction.reference)
       
        # payment_data = {
        #         "name": settings.SERVICE_GATEWAY,
        #         "authentication_token": settings.AUTH_TOKEN_GATEWAY,
        #         "currency": "xof",
        #         "operation_token": settings.OPERATION_TOKEN_GATEWAY,
        #         "order": transaction.reference,
        #         "transaction_amount": total_payment
        #     }
        payment_data = {
            "transaction_id": transaction.reference,
            'currency' : "XOF",
            "amount": amount_to_cinetpay,  # Montant avec commission TIM CASH
            "description": transaction.description,
            "recipient_phone": current_user.phone , # ⚠️ Numéro associé au wallet
            "notify_url": f"{settings.CINETPAY_CALLBACK_URL}",
            "return_url": f"{settings.APP_BASE_URL}/payment/success",
            'customer_name' :current_user.full_name,                              
            'customer_surname' : current_user.last_name, 
        }

        
        print(f"Transcation data {payment_data}")

        print(f"📤 Envoi à CinetPay: {amount_to_cinetpay} FCFA")

        # Appeler CinetPay
        # Appeler CinetPay
        # cinetpay_response = await InitPaymentWeb(payment_data).init_payment()
        cinetpay_response = await cinetpay_service.create_payment_url(payment_data)
        print(f"Réponse CinetPay: {cinetpay_response}")

        if not cinetpay_response["payment_url"]:
            db.rollback()
            raise HTTPException(
                status_code=400,
                detail="Impossible de générer le lien de paiement"
            )

        transaction.external_reference = transaction.reference
        db.commit()
        db.refresh(transaction)

        return {
            "success": True,
            "message": "Transaction créée avec succès",
            "transaction_id": transaction.id,
            "reference": transaction.reference,
            "amount": net_amount,
            "total_payment": total_payment,
            "timcash_commission": timcash_commission,
            "status": transaction.status.value,
            "user_id": current_user.id,
            # "payment_url": cinetpay_response.payment_url,
            "payment_url": cinetpay_response["payment_url"],
        }

    except Exception as e:
        db.rollback()
        raise HTTPException(
            status_code=500,
            detail=f"Erreur lors de la création de la transaction: {str(e)}"
        )

async def transaction_details(
    transaction_id: str,
    current_user: User,
    db: Session
): 
    """
    Récupérer les détails d'une transaction wallet par ID
    """
    transaction = db.query(Transaction).filter(
        Transaction.id == transaction_id,
        Transaction.user_id == current_user.id
    ).first()

    if not transaction:
        raise NotFoundException(detail="Transaction introuvable")

    return {
        "transaction_id": transaction.id,
        "user_id": transaction.user_id,
        "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,
        "created_at": transaction.created_at,
        "completed_at": transaction.completed_at,
        "wallet": transaction.wallet,
        "currency": transaction.currency
    }
async def encaissement_safe(
    request_data: WalletTransactionRequest,
    current_user: User,   # vendeur
    db: Session
):
    """
    Encaissement : le vendeur (current_user) saisit un montant à encaisser.
    - Le client (identifié par téléphone) est débité du montant exact
    - Le vendeur est crédité du montant exact
    - Pas de frais
    - Support des cartes NFC physiques
    """
    try:
        # Trouver le client qui paie
        client = db.query(User).filter(User.phone == request_data.phone).first()
        if not client:
            raise HTTPException(status_code=404, detail="Client introuvable")

        if client.id == current_user.id:
            raise HTTPException(status_code=400, detail="Vendeur et client doivent être différents")

        # Wallets
        client_wallet = get_user_wallet(client.id, db)              # client débité
        vendeur_wallet = get_user_wallet(current_user.id, db)       # vendeur crédité

        # Débit / Crédit sans frais
        if client_wallet.balance < request_data.amount:
            raise HTTPException(status_code=400, detail="Solde client insuffisant")

        if vendeur_wallet.max_balance and (vendeur_wallet.balance + request_data.amount) > vendeur_wallet.max_balance:
            raise HTTPException(status_code=400, detail="Le compte vendeur atteindrait sa limite")

        client_wallet.balance -= request_data.amount       # client débité du montant exact
        vendeur_wallet.balance += request_data.amount     # vendeur crédité du montant exact

        # Créer les transactions
        transfer_id = str(uuid.uuid4())

        # Transaction client
        client_txn = Transaction(
            id=str(uuid.uuid4()),
            user_id=client.id,
            transaction_type=TransactionType.NFC_DEPOSIT,
            amount=-request_data.amount,
            commission_amount=0.0,
            commission_rate=0.0,
            status=TransactionStatus.COMPLETED,
            description=f"Encaissement par {current_user.full_name}",
            reference=f"ENC-OUT-{transfer_id[:8]}",
            external_reference=transfer_id
        )

        # Transaction vendeur
        vendeur_txn = Transaction(
            id=str(uuid.uuid4()),
            user_id=current_user.id,
            transaction_type=TransactionType.NFC_WITHDRAWAL,
            amount=request_data.amount,
            commission_amount=0.0,
            commission_rate=0.0,
            status=TransactionStatus.COMPLETED,
            description=f"Encaissement du client {client.full_name}",
            reference=f"ENC-IN-{transfer_id[:8]}",
            external_reference=transfer_id
        )

        db.add(client_txn)
        db.add(vendeur_txn)

        db.commit()

        return {
            "transfer_id": transfer_id,
            "amount": request_data.amount,
            "fee": 0.0,  # plus de frais
            "client": client.full_name,
            "vendeur": current_user.full_name,
            "status": "completed"
        }

    except Exception as e:
        db.rollback()
        logger.error(f"Erreur encaissement: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Erreur lors de l'encaissement: {str(e)}")
    

async def rechargement_wallet(
    request_data: WalletTransactionRequest,
    current_user: User,   # vendeur
    db: Session
):
    """
    Rechargement de wallet avec paiement en espèces et notifications.
    Calcul dynamique de la commission : 20% du montant.
    Répartition : 12% entreprise (prélevé sur le vendeur), 8% vendeur.
    """

    try:
        # 1. Trouver le client
        client = db.query(User).filter(User.phone == request_data.phone).first()
        if not client:
            raise HTTPException(status_code=404, detail="Client introuvable")
        if client.id == current_user.id:
            raise HTTPException(status_code=400, detail="Vendeur et client doivent être différents")

        # 2. Wallets
        client_wallet = get_user_wallet(client.id, db)
        vendeur_wallet = get_user_wallet(current_user.id, db)
        admin_stock = get_admin_stock(db)

        # 3. Montants dynamiques
         # ce que le client veut sur son wallet
        commission_rates = CommissionService.get_recharge_commission_rates(db)

        # 3. Calculer les montants avec les taux configurables
        recharge_amount = request_data.amount  # Montant que le client veut recevoir
        commission_calculation = CommissionService.calculate_commissions(recharge_amount, commission_rates)
        commission_total = recharge_amount * 0.10  # 20% de commission
        admin_fee = commission_total * 0.06 / 0.10  # 12% prélevé sur le vendeur
        vendeur_fee = commission_total - admin_fee  # 8% vendeur
        total_debit_vendeur = recharge_amount + admin_fee  # montant que le vendeur doit avancer
        client_payment = recharge_amount + commission_total  # montant total payé par le client (cash)

        # 4. Vérifier solde vendeur
        if vendeur_wallet.balance < total_debit_vendeur:
            raise HTTPException(status_code=400, detail="Solde vendeur insuffisant pour effectuer le rechargement")

        # 5. Débit / Crédit wallets
        vendeur_wallet.balance -= total_debit_vendeur
        client_wallet.balance += recharge_amount
        admin_stock.balance += admin_fee
        admin_stock.total_commissions += admin_fee

        # 6. Créer transactions
        transfer_id = str(uuid.uuid4())

        client_txn = Transaction(
            id=str(uuid.uuid4()),
            user_id=client.id,
            transaction_type=TransactionType.RECHARGE_BY_BUSINESS,
            amount=recharge_amount,
            commission_amount=commission_total,
            commission_rate=commission_total / client_payment,
            status=TransactionStatus.COMPLETED,
            description=f"Recharge effectuée via {current_user.full_name}",
            reference=f"RCG-OUT-{transfer_id[:8]}",
            external_reference=transfer_id
        )

        vendeur_txn = Transaction(
            id=str(uuid.uuid4()),
            user_id=current_user.id,
            transaction_type=TransactionType.RECHARGE_BY_BUSINESS,
            amount=-total_debit_vendeur,
            commission_amount=admin_fee,
            commission_rate=admin_fee / total_debit_vendeur,
            status=TransactionStatus.COMPLETED,
            description=f"Débit pour rechargement client {client.full_name}",
            reference=f"RCG-DEB-{transfer_id[:8]}",
            external_reference=transfer_id
        )

        db.add_all([client_txn, vendeur_txn])

        # 7. Notifications
        notifications = [
            Notification(
                id=str(uuid.uuid4()),
                user_id=client.id,
                title="Wallet crédité",
                message=f"Votre wallet a été crédité de {recharge_amount}.",
                type="wallet_recharge",
                priority=NotificationPriority.HIGH,
                amount=recharge_amount,
                merchant=current_user.full_name,
                created_at=datetime.utcnow()
            ),
            Notification(
                id=str(uuid.uuid4()),
                user_id=current_user.id,
                title="Wallet débité",
                message=f"Votre wallet a été débité de {total_debit_vendeur} pour recharger le client {client.full_name}.",
                type="wallet_debit",
                priority=NotificationPriority.HIGH,
                amount=total_debit_vendeur,
                merchant=client.full_name,
                created_at=datetime.utcnow()
            ),
        ]

        db.add_all(notifications)

        # 8. Commit final
        db.commit()

        # 9. Retour de la réponse
        return {
            "transfer_id": transfer_id,
            "client_payment": client_payment,
            "recharge_amount": recharge_amount,
            "total_debit_vendeur": total_debit_vendeur,
            "admin_fee": admin_fee,
            "vendeur_fee": vendeur_fee,
            "client": client.full_name,
            "vendeur": current_user.full_name,
            "status": "completed"
        }

    except Exception as e:
        db.rollback()
        logger.error(f"Erreur rechargement: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Erreur lors du rechargement: {str(e)}")
 
    
async def transfert_to_client(
    request_data: WalletTransactionRequest,
    current_user: User,  # client qui envoie
    db: Session
):
    """
    Transfert d'argent d'un client vers un autre client.
    Commission : 1% prélevé sur le client qui envoie.
    """
    try:
        # 1. Trouver le bénéficiaire
        recipient = db.query(User).filter(User.phone == request_data.phone).first()
        if not recipient:
            raise HTTPException(status_code=404, detail="Client destinataire introuvable")
        if recipient.id == current_user.id:
            raise HTTPException(status_code=400, detail="Impossible d'envoyer de l'argent à soi-même")

        # 2. Récupération des wallets
        sender_wallet = get_user_wallet(current_user.id, db)
        recipient_wallet = get_user_wallet(recipient.id, db)
        admin_stock = get_admin_stock(db)  # pour stocker la commission

        # 3. Calculs des montants
        amount = request_data.amount
        commission = amount * 0.01  # 1%
        total_debit = amount + commission

        # 4. Vérification du solde
        if sender_wallet.balance < total_debit:
            raise HTTPException(status_code=400, detail="Solde insuffisant pour effectuer le transfert")

        # 5. Mouvement des soldes
        sender_wallet.balance -= total_debit
        recipient_wallet.balance += amount
        admin_stock.balance += commission
        admin_stock.total_commissions += commission

        # 6. Enregistrement des transactions
        transfer_id = str(uuid.uuid4())

        sender_txn = Transaction(
            id=str(uuid.uuid4()),
            user_id=current_user.id,
            transaction_type=TransactionType.MOBILE_TRANSFER,
            amount=-total_debit,
            commission_amount=commission,
            commission_rate=0.01,
            status=TransactionStatus.COMPLETED,
            description=f"Transfert de {amount} à {recipient.full_name}",
            reference=f"TRF-OUT-{transfer_id[:8]}",
            external_reference=transfer_id
        )

        recipient_txn = Transaction(
            id=str(uuid.uuid4()),
            user_id=recipient.id,
            transaction_type=TransactionType.MOBILE_TRANSFER,
            amount=amount,
            commission_amount=0,
            commission_rate=0,
            status=TransactionStatus.COMPLETED,
            description=f"Réception de {amount} de {current_user.full_name}",
            reference=f"TRF-IN-{transfer_id[:8]}",
            external_reference=transfer_id
        )

        db.add_all([sender_txn, recipient_txn])

        # 7. Notifications
        notifications = [
            Notification(
                id=str(uuid.uuid4()),
                user_id=current_user.id,
                title="Transfert effectué",
                message=f"Vous avez envoyé {amount} XOF à {recipient.full_name}. Frais : {commission} XOF.",
                type="wallet_debit",
                priority=NotificationPriority.MEDIUM,
                amount=total_debit,
                merchant=recipient.full_name,
                created_at=datetime.utcnow()
            ),
            Notification(
                id=str(uuid.uuid4()),
                user_id=recipient.id,
                title="Transfert reçu",
                message=f"Vous avez reçu {amount} XOF de {current_user.full_name}.",
                type="wallet_credit",
                priority=NotificationPriority.HIGH,
                amount=amount,
                merchant=current_user.full_name,
                created_at=datetime.utcnow()
            )
        ]
        db.add_all(notifications)

        # 8. Commit final
        db.commit()

        # 9. Réponse
        return {
            "transfer_id": transfer_id,
            "amount_sent": amount,
            "commission": commission,
            "total_debit": total_debit,
            "sender": current_user.full_name,
            "recipient": recipient.full_name,
            "status": "completed"
        }

    except Exception as e:
        db.rollback()
        logger.error(f"Erreur transfert client-client: {str(e)}")
        raise HTTPException(status_code=500, detail="Erreur interne lors du transfert")