from typing import Optional
from sqlalchemy.orm import Session
from models.user import User
from models.task import Task, Submission, Review
from models.notification import Notification, UserNotificationPreference, NotificationType, NotificationPriority
import logging

# Set up logging for notifications
logger = logging.getLogger(__name__)


class NotificationService:
    """Notification service for creating and managing notifications."""
    
    def _create_notification(
        self,
        db: Session,
        user_id: int,
        type: NotificationType,
        title: str,
        message: str,
        priority: NotificationPriority = NotificationPriority.NORMAL,
        project_id: Optional[int] = None,
        task_id: Optional[int] = None,
        submission_id: Optional[int] = None
    ) -> Notification:
        """Create a notification in the database."""
        try:
            # Check user preferences
            preferences = db.query(UserNotificationPreference).filter(
                UserNotificationPreference.user_id == user_id
            ).first()
            
            # Create default preferences if they don't exist
            if not preferences:
                preferences = UserNotificationPreference(user_id=user_id)
                db.add(preferences)
                db.commit()
            
            # Check if in-app notifications are enabled for this type
            if not preferences.inapp_enabled:
                return None
            
            type_pref_map = {
                NotificationType.TASK_ASSIGNED: preferences.inapp_task_assigned,
                NotificationType.TASK_STATUS_CHANGED: preferences.inapp_task_status_changed,
                NotificationType.SUBMISSION_REVIEWED: preferences.inapp_submission_reviewed,
                NotificationType.WORK_SUBMITTED: preferences.inapp_work_submitted,
                NotificationType.DEADLINE_APPROACHING: preferences.inapp_deadline_approaching,
                NotificationType.PROJECT_UPDATE: preferences.inapp_project_update,
                NotificationType.COMMENT_ADDED: preferences.inapp_comment_added,
            }
            
            if not type_pref_map.get(type, True):
                return None
            
            # Create notification
            notification = Notification(
                user_id=user_id,
                type=type,
                priority=priority,
                title=title,
                message=message,
                project_id=project_id,
                task_id=task_id,
                submission_id=submission_id
            )
            
            db.add(notification)
            db.commit()
            db.refresh(notification)
            
            logger.info(f"Created notification {notification.id} for user {user_id}: {title}")
            
            # TODO: Send email if email notifications are enabled
            if preferences.email_enabled and type_pref_map.get(type, True):
                self._send_email_notification(notification, preferences)
            
            return notification
            
        except Exception as e:
            logger.error(f"Failed to create notification: {str(e)}")
            db.rollback()
            return None
    
    def _send_email_notification(self, notification: Notification, preferences: UserNotificationPreference):
        """Send email notification (placeholder for future implementation)."""
        # TODO: Implement actual email sending
        logger.info(f"Email notification would be sent for notification {notification.id}")
    
    def notify_submission_reviewed(
        self,
        db: Session,
        submission: Submission,
        review: Review,
        reviewer: User
    ):
        """Notify artist when their submission is reviewed."""
        try:
            artist = submission.user
            decision_text = "approved" if review.decision == "approved" else "requires retakes"
            
            title = f"Submission {decision_text}"
            message = f"Your submission for task '{submission.task.name}' has been {decision_text} by {reviewer.first_name} {reviewer.last_name}"
            
            if review.feedback:
                message += f"\n\nFeedback: {review.feedback}"
            
            priority = NotificationPriority.HIGH if review.decision == "retake" else NotificationPriority.NORMAL
            
            self._create_notification(
                db=db,
                user_id=artist.id,
                type=NotificationType.SUBMISSION_REVIEWED,
                title=title,
                message=message,
                priority=priority,
                project_id=submission.task.project_id,
                task_id=submission.task_id,
                submission_id=submission.id
            )
            
        except Exception as e:
            logger.error(f"Failed to send notification for submission {submission.id}: {str(e)}")
    
    def notify_task_assigned(
        self,
        db: Session,
        task: Task,
        assigned_user: User,
        assigner: User
    ):
        """Notify user when they are assigned a task."""
        try:
            title = "New Task Assigned"
            message = f"You have been assigned a new task: '{task.name}' by {assigner.first_name} {assigner.last_name}"
            
            if task.deadline:
                message += f"\nDeadline: {task.deadline.strftime('%Y-%m-%d')}"
            
            if task.description:
                message += f"\nDescription: {task.description}"
            
            self._create_notification(
                db=db,
                user_id=assigned_user.id,
                type=NotificationType.TASK_ASSIGNED,
                title=title,
                message=message,
                priority=NotificationPriority.NORMAL,
                project_id=task.project_id,
                task_id=task.id
            )
            
        except Exception as e:
            logger.error(f"Failed to send task assignment notification for task {task.id}: {str(e)}")
    
    def notify_work_submitted(
        self,
        db: Session,
        submission: Submission,
        task: Task
    ):
        """Notify directors/coordinators when work is submitted for review."""
        try:
            from models.project import ProjectMember
            
            project_members = db.query(ProjectMember).join(User).filter(
                ProjectMember.project_id == task.project_id,
                User.role.in_(["director", "coordinator"])
            ).all()
            
            artist_name = f"{submission.user.first_name} {submission.user.last_name}"
            title = "New Submission for Review"
            message = f"New submission ready for review: '{task.name}' by {artist_name} (Version {submission.version_number})"
            
            if submission.notes:
                message += f"\nArtist notes: {submission.notes}"
            
            for member in project_members:
                self._create_notification(
                    db=db,
                    user_id=member.user_id,
                    type=NotificationType.WORK_SUBMITTED,
                    title=title,
                    message=message,
                    priority=NotificationPriority.NORMAL,
                    project_id=task.project_id,
                    task_id=task.id,
                    submission_id=submission.id
                )
            
        except Exception as e:
            logger.error(f"Failed to send submission notification for submission {submission.id}: {str(e)}")
    
    def notify_task_status_changed(
        self,
        db: Session,
        task: Task,
        old_status: str,
        new_status: str,
        changed_by: User
    ):
        """Notify relevant users when task status changes."""
        try:
            # Notify task owner if someone else changed the status
            if task.assigned_user_id and task.assigned_user_id != changed_by.id:
                title = "Task Status Updated"
                message = f"Task '{task.name}' status changed from {old_status} to {new_status} by {changed_by.first_name} {changed_by.last_name}"
                
                self._create_notification(
                    db=db,
                    user_id=task.assigned_user_id,
                    type=NotificationType.TASK_STATUS_CHANGED,
                    title=title,
                    message=message,
                    priority=NotificationPriority.NORMAL,
                    project_id=task.project_id,
                    task_id=task.id
                )
            
        except Exception as e:
            logger.error(f"Failed to send task status change notification for task {task.id}: {str(e)}")
    
    def notify_comment_added(
        self,
        db: Session,
        task: Task,
        comment_author: User,
        comment_text: str
    ):
        """Notify task assignee when a comment is added."""
        try:
            if task.assigned_user_id and task.assigned_user_id != comment_author.id:
                title = "New Comment on Task"
                message = f"{comment_author.first_name} {comment_author.last_name} commented on task '{task.name}'"
                
                if len(comment_text) > 100:
                    message += f"\n\n{comment_text[:100]}..."
                else:
                    message += f"\n\n{comment_text}"
                
                self._create_notification(
                    db=db,
                    user_id=task.assigned_user_id,
                    type=NotificationType.COMMENT_ADDED,
                    title=title,
                    message=message,
                    priority=NotificationPriority.LOW,
                    project_id=task.project_id,
                    task_id=task.id
                )
            
        except Exception as e:
            logger.error(f"Failed to send comment notification for task {task.id}: {str(e)}")


# Global notification service instance
notification_service = NotificationService()