from sqlalchemy.orm import Session
from fastapi import HTTPException, status
from typing import List, Optional
from . import repository
from .schema import NotificationCreate, NotificationUpdate, NotificationResponse
from user_management import repository as user_repo
from datetime import datetime

def _get_or_raise(db: Session, entity_id: str, repo) -> repository.Notification:
    entity = repo.get_by_id(db, entity_id)
    if not entity:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Notification not found")
    return entity

def create_notification(db: Session, data: NotificationCreate) -> NotificationResponse:
    user = user_repo.get_by_id(db, data.user_id)
    if not user:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
    
    try:
        notification = repository.create(db, data.model_dump())
        db.commit()
        db.refresh(notification)
        return NotificationResponse.model_validate(notification)
    except Exception:
        db.rollback()
        raise

def list_notifications(
    db: Session,
    limit: int,
    offset: int,
    user_id: Optional[str] = None,
    notification_type: Optional[str] = None,
    is_read: Optional[bool] = None,
    delivery_status: Optional[str] = None,
) -> List[NotificationResponse]:
    filters = {}
    if user_id:
        filters["user_id"] = user_id
    if notification_type:
        filters["notification_type"] = notification_type
    if is_read is not None:
        filters["is_read"] = is_read
    if delivery_status:
        filters["delivery_status"] = delivery_status
    
    notifications = repository.list_all(db, limit, offset, **filters)
    return [NotificationResponse.model_validate(n) for n in notifications]

def get_notification(db: Session, notification_id: str) -> NotificationResponse:
    notification = _get_or_raise(db, notification_id, repository)
    return NotificationResponse.model_validate(notification)

def update_notification(db: Session, notification_id: str, data: NotificationUpdate) -> NotificationResponse:
    notification = _get_or_raise(db, notification_id, repository)
    
    update_data = data.model_dump(exclude_unset=True)
    
    if "user_id" in update_data:
        user = user_repo.get_by_id(db, update_data["user_id"])
        if not user:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
    
    try:
        updated = repository.update(db, notification_id, update_data)
        db.commit()
        db.refresh(updated)
        return NotificationResponse.model_validate(updated)
    except Exception:
        db.rollback()
        raise

def delete_notification(db: Session, notification_id: str) -> dict:
    notification = _get_or_raise(db, notification_id, repository)
    
    try:
        repository.delete(db, notification_id)
        db.commit()
        return {"message": "Notification deleted successfully"}
    except Exception:
        db.rollback()
        raise

def get_unread_notifications(db: Session, user_id: str, limit: int, offset: int) -> List[NotificationResponse]:
    user = user_repo.get_by_id(db, user_id)
    if not user:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
    
    notifications = repository.get_unread_by_user(db, user_id, limit, offset)
    return [NotificationResponse.model_validate(n) for n in notifications]

def mark_notification_as_read(db: Session, notification_id: str) -> NotificationResponse:
    notification = _get_or_raise(db, notification_id, repository)
    
    if notification.is_read:
        return NotificationResponse.model_validate(notification)
    
    try:
        updated = repository.mark_as_read(db, notification_id)
        db.commit()
        db.refresh(updated)
        return NotificationResponse.model_validate(updated)
    except Exception:
        db.rollback()
        raise

def mark_all_as_read(db: Session, user_id: str) -> dict:
    user = user_repo.get_by_id(db, user_id)
    if not user:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
    
    try:
        count = repository.mark_all_as_read_for_user(db, user_id)
        db.commit()
        return {"message": f"{count} notifications marked as read"}
    except Exception:
        db.rollback()
        raise