"""
Routes API pour les transferts Mobile Money via CinetPay
"""
from fastapi import APIRouter, Depends, HTTPException, status, Request
from sqlalchemy.orm import Session
from typing import List
import uuid
from datetime import datetime
import logging

from database import get_db
from models.models import User, Wallet, Transaction, TransactionType, TransactionStatus, PaymentMethod
from schemas.mobile_money import (
    MobileMoneyTransferRequest,
    MobileMoneyTransferResponse,
    TransferStatusRequest,
    TransferStatusResponse,
    AddContactRequest,
    MobileMoneyOperator
)
from services.cinetpay_service import CinetPayService
from utility.auth_token import get_current_user

router = APIRouter()
logger = logging.getLogger(__name__)

def get_user_wallet(user_id: str, db: Session) -> Wallet:
    """Récupérer le wallet d'un utilisateur"""
    wallet = db.query(Wallet).filter(Wallet.user_id == user_id).first()
    if not wallet:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Wallet not found"
        )
    return wallet

@router.post("/mobile-money/transfer", response_model=MobileMoneyTransferResponse)
async def transfer_to_mobile_money(
    request: Request,
    transfer_request: MobileMoneyTransferRequest,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    Transférer de l'argent du wallet TIM CASH vers un compte Mobile Money
    
    Opérateurs supportés:
    - Wave (Sénégal)
    - Orange Money (CI, ML, SN)
    - MTN Money (CI)
    - Moov Money (CI)
    """
    try:
        # Vérifier si le compte est bloqué
        from middleware.account_blocking import check_account_blocked
        check_account_blocked(current_user, allow_recharge=False)

        logger.info(f"💸 Transfert Mobile Money demandé par {current_user.email}")
        logger.info(f"   Montant: {transfer_request.amount} FCFA")
        logger.info(f"   Vers: {transfer_request.phone} ({transfer_request.operator.value})")

        # 1. Vérifier le wallet de l'utilisateur
        wallet = get_user_wallet(current_user.id, db)
        
        # 2. Calculer les frais (2% pour les transferts Mobile Money)
        transfer_fee = transfer_request.amount * 0.02
        total_amount = transfer_request.amount + transfer_fee
        
        # 3. Vérifier le solde
        if wallet.balance < total_amount:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Solde insuffisant. Vous avez {wallet.balance} FCFA, besoin de {total_amount} FCFA (incluant frais de {transfer_fee} FCFA)"
            )
        
        # 4. Créer une transaction en attente
        transaction_id = f"MM-{str(uuid.uuid4())[:8].upper()}"
        transaction = Transaction(
            id=str(uuid.uuid4()),
            user_id=current_user.id,
            transaction_type=TransactionType.MOBILE_MONEY_TRANSFER,
            amount=-total_amount,  # Négatif car c'est une sortie
            commission_amount=transfer_fee,
            commission_rate=0.02,
            status=TransactionStatus.PENDING,
            description=f"Transfert Mobile Money vers {transfer_request.operator.value} - {transfer_request.phone}",
            reference=transaction_id,
            payment_method=PaymentMethod.MOBILE_MONEY,
            merchant_name=transfer_request.operator.value
        )
        
        db.add(transaction)
        db.commit()
        db.refresh(transaction)
        
        # 5. Obtenir le préfixe pays selon l'opérateur
        prefix = CinetPayService.get_country_prefix(transfer_request.operator.value)
        
        # 6. Initier le transfert via CinetPay
        cinetpay_result = CinetPayService.send_money(
            amount=transfer_request.amount,
            phone=transfer_request.phone,
            prefix=prefix,
            transaction_id=transaction_id,
            notify_url=f"{request.base_url}api/mobile-money/callback"
        )
        
        if not cinetpay_result.get("success"):
            # Échec du transfert CinetPay
            transaction.status = TransactionStatus.FAILED
            db.commit()
            
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Échec du transfert: {cinetpay_result.get('error', 'Erreur inconnue')}"
            )
        
        # 7. Débiter le wallet (le transfert est en cours)
        wallet.balance -= total_amount
        transaction.status = TransactionStatus.PENDING
        transaction.external_reference = cinetpay_result.get("data", {}).get("reference")
        
        db.commit()
        
        logger.info(f"✅ Transfert initié avec succès: {transaction_id}")
        
        return MobileMoneyTransferResponse(
            success=True,
            transaction_id=transaction_id,
            amount=transfer_request.amount,
            phone=transfer_request.phone,
            operator=transfer_request.operator.value,
            status="pending",
            message="Transfert en cours de traitement",
            cinetpay_reference=transaction.external_reference
        )
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"❌ Erreur transfert Mobile Money: {str(e)}")
        db.rollback()
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Erreur lors du transfert: {str(e)}"
        )

@router.get("/mobile-money/status/{transaction_id}", response_model=TransferStatusResponse)
async def check_transfer_status(
    transaction_id: str,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    Vérifier le statut d'un transfert Mobile Money
    """
    try:
        # 1. Récupérer la transaction locale
        transaction = db.query(Transaction).filter(
            Transaction.reference == transaction_id,
            Transaction.user_id == current_user.id
        ).first()
        
        if not transaction:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Transaction non trouvée"
            )
        
        # 2. Si la transaction est déjà complétée ou échouée, retourner le statut
        if transaction.status in [TransactionStatus.COMPLETED, TransactionStatus.FAILED]:
            return TransferStatusResponse(
                success=True,
                transaction_id=transaction_id,
                status=transaction.status.value,
                amount=abs(transaction.amount - transaction.commission_amount),
                phone=transaction.merchant_name,
                operator=transaction.merchant_name,
                completed_at=transaction.completed_at.isoformat() if transaction.completed_at else None
            )
        
        # 3. Vérifier le statut auprès de CinetPay
        cinetpay_result = CinetPayService.check_transfer_status(transaction_id)
        
        if cinetpay_result.get("success"):
            cinetpay_status = cinetpay_result.get("status", "").lower()
            
            # Mettre à jour le statut local selon CinetPay
            if cinetpay_status in ["completed", "success", "00"]:
                transaction.status = TransactionStatus.COMPLETED
                transaction.completed_at = datetime.utcnow()
            elif cinetpay_status in ["failed", "error", "01"]:
                transaction.status = TransactionStatus.FAILED
                # Rembourser le wallet en cas d'échec
                wallet = get_user_wallet(current_user.id, db)
                wallet.balance += abs(transaction.amount)
            
            db.commit()
        
        return TransferStatusResponse(
            success=True,
            transaction_id=transaction_id,
            status=transaction.status.value,
            amount=abs(transaction.amount - transaction.commission_amount),
            phone=transaction.merchant_name,
            operator=transaction.merchant_name,
            completed_at=transaction.completed_at.isoformat() if transaction.completed_at else None,
            error=cinetpay_result.get("error") if not cinetpay_result.get("success") else None
        )
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"❌ Erreur vérification statut: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Erreur lors de la vérification: {str(e)}"
        )

@router.post("/mobile-money/add-contact")
async def add_mobile_money_contact(
    contact: AddContactRequest,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    Ajouter un contact Mobile Money pour faciliter les transferts futurs
    """
    try:
        prefix = CinetPayService.get_country_prefix(contact.operator.value)
        
        contacts_data = [{
            "prefix": prefix,
            "phone": contact.phone,
            "name": contact.name,
            "surname": contact.surname,
            "email": contact.email or ""
        }]
        
        result = CinetPayService.add_contact(contacts_data)
        
        if not result.get("success"):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Échec ajout contact: {result.get('error', 'Erreur inconnue')}"
            )
        
        return {
            "success": True,
            "message": "Contact ajouté avec succès",
            "data": result.get("data")
        }
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"❌ Erreur ajout contact: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Erreur lors de l'ajout du contact: {str(e)}"
        )

@router.post("/mobile-money/callback")
async def mobile_money_callback(
    request: Request,
    db: Session = Depends(get_db)
):
    """
    Callback CinetPay pour les notifications de transfert
    """
    try:
        data = await request.json()
        logger.info(f"📥 Callback CinetPay reçu: {data}")
        
        transaction_id = data.get("transaction_id")
        status_code = data.get("status")
        
        if not transaction_id:
            return {"status": "error", "message": "Missing transaction_id"}
        
        # Récupérer la transaction
        transaction = db.query(Transaction).filter(
            Transaction.reference == transaction_id
        ).first()
        
        if not transaction:
            logger.warning(f"⚠️ Transaction non trouvée: {transaction_id}")
            return {"status": "error", "message": "Transaction not found"}
        
        # Mettre à jour le statut
        if status_code in ["00", "ACCEPTED", "completed"]:
            transaction.status = TransactionStatus.COMPLETED
            transaction.completed_at = datetime.utcnow()
            logger.info(f"✅ Transfert complété: {transaction_id}")
        elif status_code in ["01", "REFUSED", "failed"]:
            transaction.status = TransactionStatus.FAILED
            # Rembourser le wallet
            wallet = db.query(Wallet).filter(Wallet.user_id == transaction.user_id).first()
            if wallet:
                wallet.balance += abs(transaction.amount)
            logger.warning(f"❌ Transfert échoué: {transaction_id}")
        
        db.commit()
        
        return {"status": "success", "message": "Callback processed"}
        
    except Exception as e:
        logger.error(f"❌ Erreur callback: {str(e)}")
        return {"status": "error", "message": str(e)}

@router.get("/mobile-money/operators")
async def get_supported_operators():
    """
    Obtenir la liste des opérateurs Mobile Money supportés
    """
    return {
        "operators": [
            {
                "code": "wave",
                "name": "Wave",
                "country": "Sénégal",
                "prefix": "221",
                "logo": "wave_logo.png"
            },
            {
                "code": "orange_money",
                "name": "Orange Money",
                "country": "Multi-pays",
                "prefix": "225",  # CI par défaut
                "logo": "orange_money_logo.png"
            },
            {
                "code": "mtn_money",
                "name": "MTN Money",
                "country": "Côte d'Ivoire",
                "prefix": "225",
                "logo": "mtn_money_logo.png"
            },
            {
                "code": "moov_money",
                "name": "Moov Money",
                "country": "Côte d'Ivoire",
                "prefix": "225",
                "logo": "moov_money_logo.png"
            }
        ]
    }
