from django.utils import timezone


def _notification_exists_today(SystemNotification, recipient, title, link):
    today = timezone.now().date()
    return SystemNotification.objects.filter(
        recipient=recipient,
        title=title,
        link=link,
        created_at__date=today
    ).exists()


def notify_user(*, user, title, message='', category='system', link=''):
    from task_management.models import SystemNotification
    if not user:
        return None
    if _notification_exists_today(SystemNotification, user, title, link):
        return None
    return SystemNotification.notify(
        recipient=user,
        title=title,
        message=message,
        category=category,
        link=link
    )


def notify_users(*, users, title, message='', category='system', link=''):
    created = []
    for user in users:
        item = notify_user(user=user, title=title, message=message, category=category, link=link)
        if item:
            created.append(item)
    return created


def notify_activity(*, actor, action_display, target_title, target_type, project=None, details='', link=''):
    """
    Broadcast an activity notification to ALL staff (except the actor themselves).
    Called after any significant user action.
    """
    from django.contrib.auth import get_user_model
    from task_management.models import StaffProfile

    User = get_user_model()

    actor_name = actor.get_full_name() or actor.username
    project_suffix = f' on {project.name}' if project else ''
    title = f'{actor_name} {action_display} {target_title}{project_suffix}'

    # Notify all active staff members except the actor
    staff_users = User.objects.filter(
        staff_profile__is_active=True,
        is_active=True
    ).exclude(pk=actor.pk)

    notify_users(
        users=staff_users,
        title=title,
        message=details or f'{actor_name} performed action: {action_display} on {target_title}',
        category='system',
        link=link,
    )


def create_approval_request(*, module, action, target, summary, requested_by, details=''):
    from task_management.models import ApprovalRequest
    return ApprovalRequest.request_for(
        module=module,
        action=action,
        target=target,
        summary=summary,
        requested_by=requested_by,
        details=details
    )


def on_task_status_changed(*, task, old_status, actor):
    team = task.assigned_to.exclude(pk=actor.pk if actor else None)
    title = f'Task updated: {task.title}'
    message = f'Status changed from {old_status} to {task.status}.'
    notify_users(
        users=team,
        title=title,
        message=message,
        category='task',
        link=f'/staff/tasks/{task.id}/'
    )
    # Also broadcast to all staff
    notify_activity(
        actor=actor,
        action_display=f'moved task from {old_status} to {task.status}:',
        target_title=task.title,
        target_type='Task',
        project=task.project,
        link=f'/staff/tasks/{task.id}/'
    )


def on_document_published(*, document_request, actor=None):
    project = document_request.project
    portal_profile = getattr(project.client, 'portal_profile', None)
    recipient = portal_profile.user if portal_profile else None
    notify_user(
        user=recipient,
        title=f'New document request: {document_request.title}',
        message='A new document has been published for your action.',
        category='document',
        link='/documents/'
    )
    staff_users = project.team_members.exclude(pk=actor.pk if actor else None)
    notify_users(
        users=staff_users,
        title=f'Document published: {document_request.title}',
        message=f'Published to client portal for {project.client.company_name}.',
        category='document',
        link=f'/staff/projects/{project.id}/documents/'
    )
    if actor:
        notify_activity(
            actor=actor,
            action_display='published document:',
            target_title=document_request.title,
            target_type='DocumentRequest',
            project=project,
            link=f'/staff/projects/{project.id}/documents/'
        )


def on_asset_published(*, asset_request, actor=None):
    project = asset_request.project
    portal_profile = getattr(project.client, 'portal_profile', None)
    recipient = portal_profile.user if portal_profile else None
    notify_user(
        user=recipient,
        title=f'Asset requested: {asset_request.title}',
        message='A new file upload request is waiting in your client portal.',
        category='asset',
        link='/assets/'
    )
    staff_users = project.team_members.exclude(pk=actor.pk if actor else None)
    notify_users(
        users=staff_users,
        title=f'Asset request sent: {asset_request.title}',
        message=f'Request pushed to client portal for {project.client.company_name}.',
        category='asset',
        link=f'/staff/projects/{project.id}/assets/'
    )
    if actor:
        notify_activity(
            actor=actor,
            action_display='sent asset request to portal:',
            target_title=asset_request.title,
            target_type='AssetRequest',
            project=project,
            link=f'/staff/projects/{project.id}/assets/'
        )


def on_activity_logged(*, actor, action, target_title, target_type, project=None, details='', link=''):
    """
    Generic hook — call this after any ActivityLog.log() to fan-out notifications.
    Maps action codes to human-readable verbs.
    """
    verb_map = {
        'created': 'created',
        'updated': 'updated',
        'deleted': 'archived',
        'commented': 'commented on',
        'signed': 'signed',
        'uploaded': 'uploaded',
        'moved': 'moved',
        'assigned': 'assigned',
    }
    action_display = verb_map.get(action, action)
    notify_activity(
        actor=actor,
        action_display=f'{action_display}:',
        target_title=target_title,
        target_type=target_type,
        project=project,
        details=details,
        link=link,
    )


def run_deadline_rules():
    """Lightweight workflow checks — safe to call from management commands."""
    from task_management.models import Task, DocumentRequest, AssetRequest

    today = timezone.now().date()
    soon = today + timezone.timedelta(days=2)

    for task in Task.objects.filter(
        is_active=True,
        status__in=['todo', 'in_progress', 'review'],
        due_date__isnull=False,
        due_date__lte=soon,
    ).prefetch_related('assigned_to'):
        for user in task.assigned_to.all():
            notify_user(
                user=user,
                title=f'Task due soon: {task.title}',
                message=f'Due date: {task.due_date}.',
                category='task',
                link=f'/staff/tasks/{task.id}/'
            )

    for doc in DocumentRequest.objects.filter(
        is_active=True, portal_visible=True, signed=False,
        deadline__isnull=False, deadline__lte=soon
    ).select_related('project', 'project__client'):
        portal_profile = getattr(doc.project.client, 'portal_profile', None)
        recipient = portal_profile.user if portal_profile else None
        notify_user(
            user=recipient,
            title=f'Document deadline soon: {doc.title}',
            message=f'Please sign before {doc.deadline}.',
            category='document',
            link='/documents/'
        )

    for asset in AssetRequest.objects.filter(
        is_active=True, portal_visible=True, status='requested',
        deadline__isnull=False, deadline__lte=soon
    ).select_related('project', 'project__client'):
        portal_profile = getattr(asset.project.client, 'portal_profile', None)
        recipient = portal_profile.user if portal_profile else None
        notify_user(
            user=recipient,
            title=f'Asset deadline soon: {asset.title}',
            message=f'Please upload before {asset.deadline}.',
            category='asset',
            link='/assets/'
        )