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, **filters) -> List[Notification]:
    query = db.query(Notification)
    
    if "user_id" in filters and filters["user_id"]:
        query = query.filter(Notification.user_id == filters["user_id"])
    
    if "notification_type" in filters and filters["notification_type"]:
        query = query.filter(Notification.notification_type == filters["notification_type"])
    
    if "is_read" in filters and filters["is_read"] is not None:
        query = query.filter(Notification.is_read == filters["is_read"])
    
    if "delivery_status" in filters and filters["delivery_status"]:
        query = query.filter(Notification.delivery_status == filters["delivery_status"])
    
    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 get_unread_by_user(db: Session, user_id: str, limit: int = 20, offset: int = 0) -> List[Notification]:
    return (
        db.query(Notification)
        .filter(Notification.user_id == user_id, Notification.is_read == False)
        .order_by(Notification.created_at.desc())
        .limit(limit)
        .offset(offset)
        .all()
    )

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