from sqlalchemy.orm import Session
from typing import Optional, List
from .models import Notification


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


def list_all(
    db: Session,
    limit: int = 20,
    offset: int = 0,
    user_id: Optional[str] = None,
    is_read: Optional[bool] = None,
    notification_type: Optional[str] = None,
) -> List[Notification]:
    query = db.query(Notification)
    
    if user_id is not None:
        query = query.filter(Notification.user_id == user_id)
    
    if is_read is not None:
        query = query.filter(Notification.is_read == is_read)
    
    if notification_type is not None:
        query = query.filter(Notification.notification_type == notification_type)
    
    return query.order_by(Notification.created_at.desc()).limit(limit).offset(offset).all()


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


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


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


def mark_as_read(db: Session, entity_id: str) -> Optional[Notification]:
    from datetime import datetime
    notification = get_by_id(db, entity_id)
    if not notification:
        return None
    
    notification.is_read = True
    notification.read_at = datetime.utcnow()
    db.flush()
    return notification


def mark_all_as_read_for_user(db: Session, user_id: str) -> int:
    from datetime import datetime
    count = (
        db.query(Notification)
        .filter(Notification.user_id == user_id, Notification.is_read == False)
        .update({"is_read": True, "read_at": datetime.utcnow()}, synchronize_session=False)
    )
    db.flush()
    return count


def get_unread_count(db: Session, user_id: str) -> int:
    return db.query(Notification).filter(
        Notification.user_id == user_id,
        Notification.is_read == False
    ).count()