from sqlalchemy.orm import Session
from typing import Optional, List
from .models import Promotion, Promotionusage


def get_by_id(db: Session, entity_id: str) -> Optional[Promotion]:
    return db.query(Promotion).filter(Promotion.id == entity_id).first()


def get_by_code(db: Session, code: str) -> Optional[Promotion]:
    return db.query(Promotion).filter(Promotion.code == code).first()


def list_all(db: Session, limit: int = 20, offset: int = 0, **filters) -> List[Promotion]:
    query = db.query(Promotion)
    
    if "is_active" in filters and filters["is_active"] is not None:
        query = query.filter(Promotion.is_active == filters["is_active"])
    
    if "promotion_type" in filters and filters["promotion_type"]:
        query = query.filter(Promotion.promotion_type == filters["promotion_type"])
    
    if "search" in filters and filters["search"]:
        search_term = f"%{filters['search']}%"
        query = query.filter(
            (Promotion.name.ilike(search_term)) |
            (Promotion.code.ilike(search_term))
        )
    
    return query.order_by(Promotion.created_at.desc()).limit(limit).offset(offset).all()


def create(db: Session, data: dict) -> Promotion:
    promotion = Promotion(**data)
    db.add(promotion)
    db.flush()
    return promotion


def update(db: Session, entity_id: str, data: dict) -> Optional[Promotion]:
    promotion = get_by_id(db, entity_id)
    if not promotion:
        return None
    
    for key, value in data.items():
        setattr(promotion, key, value)
    
    db.flush()
    return promotion


def delete(db: Session, entity_id: str) -> bool:
    promotion = get_by_id(db, entity_id)
    if not promotion:
        return False
    
    db.delete(promotion)
    db.flush()
    return True


def get_usage_by_id(db: Session, entity_id: str) -> Optional[Promotionusage]:
    return db.query(Promotionusage).filter(Promotionusage.id == entity_id).first()


def list_all_usages(db: Session, limit: int = 20, offset: int = 0, **filters) -> List[Promotionusage]:
    query = db.query(Promotionusage)
    
    if "promotion_id" in filters and filters["promotion_id"]:
        query = query.filter(Promotionusage.promotion_id == filters["promotion_id"])
    
    if "user_id" in filters and filters["user_id"]:
        query = query.filter(Promotionusage.user_id == filters["user_id"])
    
    if "order_id" in filters and filters["order_id"]:
        query = query.filter(Promotionusage.order_id == filters["order_id"])
    
    return query.order_by(Promotionusage.created_at.desc()).limit(limit).offset(offset).all()


def create_usage(db: Session, data: dict) -> Promotionusage:
    usage = Promotionusage(**data)
    db.add(usage)
    db.flush()
    return usage


def update_usage(db: Session, entity_id: str, data: dict) -> Optional[Promotionusage]:
    usage = get_usage_by_id(db, entity_id)
    if not usage:
        return None
    
    for key, value in data.items():
        setattr(usage, key, value)
    
    db.flush()
    return usage


def delete_usage(db: Session, entity_id: str) -> bool:
    usage = get_usage_by_id(db, entity_id)
    if not usage:
        return False
    
    db.delete(usage)
    db.flush()
    return True


def count_usages_by_promotion_and_user(db: Session, promotion_id: str, user_id: str) -> int:
    return db.query(Promotionusage).filter(
        Promotionusage.promotion_id == promotion_id,
        Promotionusage.user_id == user_id
    ).count()