from sqlalchemy.orm import Session
from sqlalchemy import and_, or_, func
from typing import Optional, List, Dict, Any
from app.models.donation import Donation, DonationRequest
from app.schemas.donation import DonationCreate, DonationUpdate, DonationRequestCreate


class DonationCRUD:
    def get_by_id(self, db: Session, donation_id: int) -> Optional[Donation]:
        """Obtenir un don par ID"""
        return db.query(Donation).filter(Donation.id == donation_id).first()
    
    def get_all(self, db: Session, skip: int = 0, limit: int = 100) -> List[Donation]:
        """Obtenir tous les dons"""
        return db.query(Donation).offset(skip).limit(limit).all()
    
    def get_by_user(self, db: Session, user_id: int, skip: int = 0, limit: int = 100) -> List[Donation]:
        """Obtenir les dons d'un utilisateur"""
        return db.query(Donation).filter(Donation.user_id == user_id).offset(skip).limit(limit).all()
    
    def create(self, db: Session, donation_create: DonationCreate, user_id: Optional[int] = None) -> Donation:
        """Créer un nouveau don"""
        db_donation = Donation(
            **donation_create.dict(),
            user_id=user_id
        )
        db.add(db_donation)
        db.commit()
        db.refresh(db_donation)
        return db_donation
    
    def update(self, db: Session, donation_id: int, donation_update: DonationUpdate) -> Optional[Donation]:
        """Mettre à jour un don"""
        db_donation = self.get_by_id(db, donation_id)
        if not db_donation:
            return None
        
        update_data = donation_update.dict(exclude_unset=True)
        for field, value in update_data.items():
            setattr(db_donation, field, value)
        
        db.commit()
        db.refresh(db_donation)
        return db_donation
    
    def delete(self, db: Session, donation_id: int) -> bool:
        """Supprimer un don"""
        db_donation = self.get_by_id(db, donation_id)
        if not db_donation:
            return False
        
        db.delete(db_donation)
        db.commit()
        return True
    
    def search(self, db: Session, search: Optional[str] = None, category: Optional[str] = None, 
               status: Optional[str] = None, page: int = 1, per_page: int = 10) -> Dict[str, Any]:
        """Rechercher des dons avec pagination"""
        query = db.query(Donation)
        
        if search:
            search_filter = or_(
                Donation.title.ilike(f"%{search}%"),
                Donation.description.ilike(f"%{search}%"),
                Donation.location.ilike(f"%{search}%")
            )
            query = query.filter(search_filter)
        
        if category:
            query = query.filter(Donation.category == category)
        
        if status:
            query = query.filter(Donation.status == status)
        
        # Compter le total
        total = query.count()
        
        # Pagination
        offset = (page - 1) * per_page
        donations = query.offset(offset).limit(per_page).all()
        
        return {
            "data": donations,
            "total": total,
            "current_page": page,
            "per_page": per_page,
            "total_pages": (total + per_page - 1) // per_page
        }
    
    def increment_views(self, db: Session, donation_id: int) -> bool:
        """Incrémenter le nombre de vues d'un don"""
        db_donation = self.get_by_id(db, donation_id)
        if not db_donation:
            return False
        
        db_donation.views += 1
        db.commit()
        return True


class DonationRequestCRUD:
    def get_by_id(self, db: Session, request_id: int) -> Optional[DonationRequest]:
        """Obtenir une demande de don par ID"""
        return db.query(DonationRequest).filter(DonationRequest.id == request_id).first()
    
    def get_all(self, db: Session, skip: int = 0, limit: int = 100) -> List[DonationRequest]:
        """Obtenir toutes les demandes de dons"""
        return db.query(DonationRequest).offset(skip).limit(limit).all()
    
    def get_by_donation(self, db: Session, donation_id: int) -> List[DonationRequest]:
        """Obtenir les demandes pour un don spécifique"""
        return db.query(DonationRequest).filter(DonationRequest.donation_id == donation_id).all()
    
    def create(self, db: Session, request_create: DonationRequestCreate) -> DonationRequest:
        """Créer une nouvelle demande de don"""
        db_request = DonationRequest(**request_create.dict())
        db.add(db_request)
        db.commit()
        db.refresh(db_request)
        return db_request
    
    def update_status(self, db: Session, request_id: int, status: str) -> Optional[DonationRequest]:
        """Mettre à jour le statut d'une demande de don"""
        db_request = self.get_by_id(db, request_id)
        if not db_request:
            return None
        
        db_request.status = status
        db.commit()
        db.refresh(db_request)
        return db_request
    
    def delete(self, db: Session, request_id: int) -> bool:
        """Supprimer une demande de don"""
        db_request = self.get_by_id(db, request_id)
        if not db_request:
            return False
        
        db.delete(db_request)
        db.commit()
        return True


donation_crud = DonationCRUD()
donation_request_crud = DonationRequestCRUD()
