from datetime import timedelta

from django.db import transaction
from django.utils import timezone

from apps.accounts.models import User
from apps.notifications.email_delivery import send_email_using_active_config
from apps.notifications.models import Notification


FIRST_RESPONSE_SLA_HOURS = {
    "urgent": 1,
    "high": 4,
    "medium": 12,
    "low": 24,
}

RESOLUTION_SLA_HOURS = {
    "urgent": 8,
    "high": 24,
    "medium": 48,
    "low": 72,
}


def _display_name(user):
    first_name = (getattr(user, "first_name", "") or "").strip()
    last_name = (getattr(user, "last_name", "") or "").strip()
    full_name = f"{first_name} {last_name}".strip()
    return full_name or getattr(user, "mobile", "") or getattr(user, "email", "") or str(user.id)


def initialize_ticket_sla(ticket, now=None):
    now = now or timezone.now()
    priority = (ticket.priority or "medium").lower()

    first_response_hours = FIRST_RESPONSE_SLA_HOURS.get(priority, 12)
    resolution_hours = RESOLUTION_SLA_HOURS.get(priority, 48)

    ticket.first_response_due_at = now + timedelta(hours=first_response_hours)
    ticket.resolution_due_at = now + timedelta(hours=resolution_hours)


def apply_sla_and_escalation(ticket, now=None):
    now = now or timezone.now()
    changed_fields = []

    if ticket.status in {"resolved", "closed"}:
        return changed_fields

    breached = False
    if not ticket.first_response_at and ticket.first_response_due_at and now > ticket.first_response_due_at:
        breached = True
    if ticket.resolution_due_at and now > ticket.resolution_due_at:
        breached = True

    if breached and not ticket.sla_breached_at:
        ticket.sla_breached_at = now
        changed_fields.append("sla_breached_at")

    if breached:
        target_level = 1
        if ticket.resolution_due_at and now > (ticket.resolution_due_at + timedelta(hours=24)):
            target_level = 2

        if (ticket.escalation_level or 0) < target_level:
            ticket.escalation_level = target_level
            ticket.escalated_at = now
            changed_fields.extend(["escalation_level", "escalated_at"])

    return changed_fields


def _send_in_app_notification(*, user, subject, message, payload):
    recipient = user.mobile or user.email or str(user.id)
    Notification.objects.create(
        user=user,
        channel="in_app",
        recipient=recipient,
        subject=subject,
        message=message,
        payload=payload or {},
        status="sent",
        provider="internal",
        sent_at=timezone.now(),
        is_read=False,
    )


def _send_email_notification(*, user, subject, message):
    email = (getattr(user, "email", "") or "").strip()
    if not email:
        return

    result = send_email_using_active_config(
        subject=subject,
        message=message,
        recipient_list=[email],
        purpose="notification",
    )

    Notification.objects.create(
        user=user,
        channel="email",
        recipient=email,
        subject=subject,
        message=message,
        payload={},
        status="sent" if result.get("ok") else "failed",
        provider=str(result.get("provider") or "smtp"),
        sent_at=timezone.now(),
    )


def notify_ticket_event(*, ticket, actor, event_type, include_admins=False):
    actor_name = _display_name(actor)
    subject = f"Support Ticket {ticket.ticket_number}: {ticket.subject}"

    if event_type == "created":
        body = f"{actor_name} created a new support ticket."
    elif event_type == "user_reply":
        body = f"{actor_name} replied to the support ticket."
    elif event_type == "admin_reply":
        body = f"Support team replied to your ticket."
    elif event_type == "status_changed":
        body = f"Ticket status changed to {ticket.status.replace('_', ' ').title()}."
    elif event_type == "assigned":
        assignee_name = _display_name(ticket.assigned_to) if ticket.assigned_to else "Unassigned"
        body = f"Ticket assignment updated: {assignee_name}."
    elif event_type == "escalated":
        body = f"Ticket escalated to level {ticket.escalation_level}."
    else:
        body = f"Support ticket updated by {actor_name}."

    payload = {
        "ticket_id": str(ticket.id),
        "ticket_number": ticket.ticket_number,
        "status": ticket.status,
        "priority": ticket.priority,
        "event_type": event_type,
        "escalation_level": int(ticket.escalation_level or 0),
    }

    recipients = []

    if event_type in {"created", "user_reply", "escalated"}:
        if ticket.assigned_to_id:
            recipients.append(ticket.assigned_to)
        if include_admins:
            admin_qs = User.objects.filter(is_active=True).filter(is_staff=True)
            recipients.extend(list(admin_qs))
    else:
        recipients.append(ticket.user)

    deduped = {}
    for recipient in recipients:
        if not recipient:
            continue
        if recipient.id == actor.id:
            continue
        deduped[str(recipient.id)] = recipient

    with transaction.atomic():
        for recipient in deduped.values():
            _send_in_app_notification(user=recipient, subject=subject, message=body, payload=payload)
            _send_email_notification(user=recipient, subject=subject, message=body)
