"""
PX Action Center UI views - Server-rendered templates for action center console
"""

from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.contenttypes.models import ContentType
from django.core.paginator import Paginator
from django.db.models import Q, Prefetch
from django.http import JsonResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.utils import timezone
from django.views.decorators.http import require_http_methods

from apps.accounts.models import User
from apps.core.services import AuditService
from apps.organizations.models import Department, Hospital

from .forms import ManualActionForm
from .models import (
    PXAction,
    PXActionAttachment,
    PXActionLog,
    ActionStatus,
    ActionSource,
)


@login_required
def action_list(request):
    """
    PX Actions list view with advanced filters and views.

    Features:
    - Multiple views (All, My Actions, Overdue, Escalated, By Source)
    - Server-side pagination
    - Advanced filters
    - Search functionality
    - Bulk actions support
    """
    # Base queryset with optimizations
    queryset = PXAction.objects.select_related(
        "hospital", "department", "assigned_to", "approved_by", "closed_by", "content_type"
    )

    # Apply RBAC filters
    user = request.user
    # Get selected hospital for PX Admins (from middleware)
    selected_hospital = getattr(request, "tenant_hospital", None)

    if user.is_px_admin():
        # PX Admins see all, but filter by selected hospital if set
        if selected_hospital:
            queryset = queryset.filter(hospital=selected_hospital)
    elif user.is_hospital_admin() and user.hospital:
        queryset = queryset.filter(hospital=user.hospital)
    elif user.is_department_manager() and user.department:
        queryset = queryset.filter(department=user.department)
    elif user.hospital:
        queryset = queryset.filter(hospital=user.hospital)
    else:
        queryset = queryset.none()

    # View filter (My Actions, Overdue, etc.)
    view_filter = request.GET.get("view", "all")
    if view_filter == "my_actions":
        queryset = queryset.filter(assigned_to=user)
    elif view_filter == "overdue":
        queryset = queryset.filter(is_overdue=True, status__in=[ActionStatus.OPEN, ActionStatus.IN_PROGRESS])
    elif view_filter == "escalated":
        queryset = queryset.filter(escalation_level__gt=0)
    elif view_filter == "pending_approval":
        queryset = queryset.filter(status=ActionStatus.PENDING_APPROVAL)
    elif view_filter == "from_surveys":
        queryset = queryset.filter(source_type=ActionSource.SURVEY)
    elif view_filter == "from_complaints":
        queryset = queryset.filter(source_type__in=[ActionSource.COMPLAINT, ActionSource.COMPLAINT_RESOLUTION])
    elif view_filter == "from_social":
        queryset = queryset.filter(source_type=ActionSource.SOCIAL_MEDIA)

    # Apply filters from request
    status_filter = request.GET.get("status")
    if status_filter:
        queryset = queryset.filter(status=status_filter)

    severity_filter = request.GET.get("severity")
    if severity_filter:
        queryset = queryset.filter(severity=severity_filter)

    priority_filter = request.GET.get("priority")
    if priority_filter:
        queryset = queryset.filter(priority=priority_filter)

    category_filter = request.GET.get("category")
    if category_filter:
        queryset = queryset.filter(category=category_filter)

    source_type_filter = request.GET.get("source_type")
    if source_type_filter:
        queryset = queryset.filter(source_type=source_type_filter)

    hospital_filter = request.GET.get("hospital")
    if hospital_filter:
        queryset = queryset.filter(hospital_id=hospital_filter)

    department_filter = request.GET.get("department")
    if department_filter:
        queryset = queryset.filter(department_id=department_filter)

    assigned_to_filter = request.GET.get("assigned_to")
    if assigned_to_filter:
        queryset = queryset.filter(assigned_to_id=assigned_to_filter)

    # Search
    search_query = request.GET.get("search")
    if search_query:
        queryset = queryset.filter(Q(title__icontains=search_query) | Q(description__icontains=search_query))

    # Date range filters
    date_from = request.GET.get("date_from")
    if date_from:
        queryset = queryset.filter(created_at__gte=date_from)

    date_to = request.GET.get("date_to")
    if date_to:
        queryset = queryset.filter(created_at__lte=date_to)

    # Ordering
    order_by = request.GET.get("order_by", "-created_at")
    queryset = queryset.order_by(order_by)

    # Pagination
    page_size = int(request.GET.get("page_size", 25))
    paginator = Paginator(queryset, page_size)
    page_number = request.GET.get("page", 1)
    page_obj = paginator.get_page(page_number)

    # Get filter options
    hospitals = Hospital.objects.filter(status="active")
    if not user.is_px_admin() and user.hospital:
        hospitals = hospitals.filter(id=user.hospital.id)

    departments = Department.objects.filter(status="active")
    if not user.is_px_admin() and user.hospital:
        departments = departments.filter(hospital=user.hospital)

    # Get assignable users
    from apps.core.utils import get_assignable_users
    assignable_users = get_assignable_users(user.hospital)

    # Statistics
    stats = {
        "total": queryset.count(),
        "open": queryset.filter(status=ActionStatus.OPEN).count(),
        "in_progress": queryset.filter(status=ActionStatus.IN_PROGRESS).count(),
        "overdue": queryset.filter(is_overdue=True).count(),
        "pending_approval": queryset.filter(status=ActionStatus.PENDING_APPROVAL).count(),
        "my_actions": queryset.filter(assigned_to=user).count(),
    }

    context = {
        "page_obj": page_obj,
        "actions": page_obj.object_list,
        "stats": stats,
        "hospitals": hospitals,
        "departments": departments,
        "assignable_users": assignable_users,
        "status_choices": ActionStatus.choices,
        "source_choices": ActionSource.choices,
        "filters": request.GET,
        "current_view": view_filter,
    }

    return render(request, "actions/action_list.html", context)


@login_required
def action_detail(request, pk):
    """
    PX Action detail view with logs, attachments, and workflow actions.

    Features:
    - Full action details
    - Activity log timeline
    - Evidence/attachments management
    - SLA tracking with progress bar
    - Workflow actions (assign, status change, approve, add note)
    - Source object link
    """
    action = get_object_or_404(
        PXAction.objects.select_related(
            "hospital", "department", "assigned_to", "approved_by", "closed_by", "content_type"
        ).prefetch_related("logs__created_by", "attachments__uploaded_by"),
        pk=pk,
    )

    # Check access
    user = request.user
    if not user.is_px_admin():
        if user.is_hospital_admin() and action.hospital != user.hospital:
            messages.error(request, "You don't have permission to view this action.")
            return redirect("actions:action_list")
        elif user.is_department_manager() and action.department != user.department:
            messages.error(request, "You don't have permission to view this action.")
            return redirect("actions:action_list")
        elif user.hospital and action.hospital != user.hospital:
            messages.error(request, "You don't have permission to view this action.")
            return redirect("actions:action_list")

    # Get logs (timeline)
    logs = action.logs.all().order_by("-created_at")

    # Get attachments
    attachments = action.attachments.all().order_by("-created_at")
    evidence_attachments = attachments.filter(is_evidence=True)

    # Get assignable users
    from apps.core.utils import get_assignable_users
    assignable_users = get_assignable_users(action.hospital)

    # Check if overdue
    action.check_overdue()

    # Calculate SLA progress percentage
    if action.created_at and action.due_at:
        total_duration = (action.due_at - action.created_at).total_seconds()
        elapsed_duration = (timezone.now() - action.created_at).total_seconds()
        sla_progress = min(100, int((elapsed_duration / total_duration) * 100)) if total_duration > 0 else 0
    else:
        sla_progress = 0

    context = {
        "action": action,
        "logs": logs,
        "attachments": attachments,
        "evidence_attachments": evidence_attachments,
        "assignable_users": assignable_users,
        "status_choices": ActionStatus.choices,
        "sla_progress": sla_progress,
        "can_edit": user.is_px_admin() or user.is_hospital_admin() or action.assigned_to == user,
        "can_approve": user.is_px_admin(),
    }

    return render(request, "actions/action_detail.html", context)


@login_required
@require_http_methods(["POST"])
def action_assign(request, pk):
    """Assign action to user"""
    action = get_object_or_404(PXAction, pk=pk)

    # Check permission
    user = request.user
    if not (user.is_px_admin() or user.is_hospital_admin()):
        messages.error(request, "You don't have permission to assign actions.")
        return redirect("actions:action_detail", pk=pk)

    user_id = request.POST.get("user_id")
    if not user_id:
        messages.error(request, "Please select a user to assign.")
        return redirect("actions:action_detail", pk=pk)

    try:
        assignee = User.objects.get(id=user_id)
        action.assigned_to = assignee
        action.assigned_at = timezone.now()
        action.save(update_fields=["assigned_to", "assigned_at"])

        # Create log
        PXActionLog.objects.create(
            action=action,
            log_type="assignment",
            message=f"Assigned to {assignee.get_full_name()}",
            created_by=request.user,
        )

        # Audit log
        AuditService.log_event(
            event_type="assignment",
            description=f"Action assigned to {assignee.get_full_name()}",
            user=request.user,
            content_object=action,
        )

        messages.success(request, f"Action assigned to {assignee.get_full_name()}.")

    except User.DoesNotExist:
        messages.error(request, "User not found.")

    return redirect("actions:action_detail", pk=pk)


@login_required
@require_http_methods(["POST"])
def action_change_status(request, pk):
    """Change action status"""
    action = get_object_or_404(PXAction, pk=pk)

    # Check permission
    user = request.user
    if not (user.is_px_admin() or user.is_hospital_admin() or action.assigned_to == user):
        messages.error(request, "You don't have permission to change action status.")
        return redirect("actions:action_detail", pk=pk)

    new_status = request.POST.get("status")
    note = request.POST.get("note", "")

    if not new_status:
        messages.error(request, "Please select a status.")
        return redirect("actions:action_detail", pk=pk)

    # Validate status transitions
    if new_status == ActionStatus.PENDING_APPROVAL:
        if action.requires_approval:
            evidence_count = action.attachments.filter(is_evidence=True).count()
            if evidence_count == 0:
                messages.error(request, "Evidence is required before requesting approval.")
                return redirect("actions:action_detail", pk=pk)

    elif new_status == ActionStatus.APPROVED:
        if not user.is_px_admin():
            messages.error(request, "Only PX Admins can approve actions.")
            return redirect("actions:action_detail", pk=pk)
        action.approved_by = user
        action.approved_at = timezone.now()

    elif new_status == ActionStatus.CLOSED:
        action.closed_at = timezone.now()
        action.closed_by = user

    old_status = action.status
    action.status = new_status
    action.save()

    # Create log
    PXActionLog.objects.create(
        action=action,
        log_type="status_change",
        message=note or f"Status changed from {old_status} to {new_status}",
        created_by=user,
        old_status=old_status,
        new_status=new_status,
    )

    # Audit log
    AuditService.log_event(
        event_type="status_change",
        description=f"Action status changed from {old_status} to {new_status}",
        user=user,
        content_object=action,
        metadata={"old_status": old_status, "new_status": new_status},
    )

    messages.success(request, f"Action status changed to {new_status}.")
    return redirect("actions:action_detail", pk=pk)


@login_required
@require_http_methods(["POST"])
def action_add_note(request, pk):
    """Add note to action"""
    action = get_object_or_404(PXAction, pk=pk)

    note = request.POST.get("note")
    if not note:
        messages.error(request, "Please enter a note.")
        return redirect("actions:action_detail", pk=pk)

    # Create log
    PXActionLog.objects.create(action=action, log_type="note", message=note, created_by=request.user)

    messages.success(request, "Note added successfully.")
    return redirect("actions:action_detail", pk=pk)


@login_required
@require_http_methods(["POST"])
def action_escalate(request, pk):
    """Escalate action"""
    action = get_object_or_404(PXAction, pk=pk)

    # Check permission
    user = request.user
    if not (user.is_px_admin() or user.is_hospital_admin()):
        messages.error(request, "You don't have permission to escalate actions.")
        return redirect("actions:action_detail", pk=pk)

    reason = request.POST.get("reason", "")

    # Increment escalation level
    action.escalation_level += 1
    action.escalated_at = timezone.now()
    action.save(update_fields=["escalation_level", "escalated_at"])

    # Create log
    PXActionLog.objects.create(
        action=action,
        log_type="escalation",
        message=f"Action escalated (Level {action.escalation_level}). Reason: {reason}",
        created_by=user,
    )

    # Audit log
    AuditService.log_event(
        event_type="escalation",
        description=f"Action escalated to level {action.escalation_level}",
        user=user,
        content_object=action,
        metadata={"reason": reason, "escalation_level": action.escalation_level},
    )

    messages.success(request, f"Action escalated to level {action.escalation_level}.")
    return redirect("actions:action_detail", pk=pk)


@login_required
@require_http_methods(["POST"])
def action_approve(request, pk):
    """Approve action (PX Admin only)"""
    action = get_object_or_404(PXAction, pk=pk)

    # Check permission
    if not request.user.is_px_admin():
        messages.error(request, "Only PX Admins can approve actions.")
        return redirect("actions:action_detail", pk=pk)

    if action.status != ActionStatus.PENDING_APPROVAL:
        messages.error(request, "Action is not pending approval.")
        return redirect("actions:action_detail", pk=pk)

    # Approve
    action.status = ActionStatus.APPROVED
    action.approved_by = request.user
    action.approved_at = timezone.now()
    action.save()

    # Create log
    PXActionLog.objects.create(
        action=action,
        log_type="approval",
        message=f"Action approved by {request.user.get_full_name()}",
        created_by=request.user,
        old_status=ActionStatus.PENDING_APPROVAL,
        new_status=ActionStatus.APPROVED,
    )

    # Audit log
    AuditService.log_event(
        event_type="approval", description="Action approved", user=request.user, content_object=action
    )

    messages.success(request, "Action approved successfully.")
    return redirect("actions:action_detail", pk=pk)


@login_required
def action_create(request):
    """
    Create a new PX Action manually.

    Features:
    - Source type selection (including meeting types)
    - Hospital/department selection (filtered by permissions)
    - Assignment to users
    - Priority, severity, category selection
    - Due date configuration
    - Action plan input
    """
    # Check permission
    user = request.user
    if not (user.is_px_admin() or user.is_hospital_admin() or user.is_department_manager()):
        messages.error(request, "You don't have permission to create actions.")
        return redirect("actions:action_list")

    if request.method == "POST":
        form = ManualActionForm(request.POST, request=request)
        if form.is_valid():
            action = form.save(commit=False)
            action.created_by = user

            # Set status to OPEN
            action.status = ActionStatus.OPEN

            # If assigned, set assignment timestamp
            if action.assigned_to:
                action.assigned_at = timezone.now()

            action.save()

            # Create log
            PXActionLog.objects.create(
                action=action,
                log_type="status_change",
                message=f"Action created manually from {action.get_source_type_display()}",
                created_by=user,
            )

            # Audit log
            AuditService.log_event(
                event_type="action_created",
                description=f"Manual action created from {action.get_source_type_display()}",
                user=user,
                content_object=action,
            )

            # Notify assigned user
            if action.assigned_to:
                from apps.notifications.services import NotificationService

                NotificationService.send_notification(
                    recipient=action.assigned_to,
                    title=f"New Action Assigned: {action.title}",
                    message=f"You have been assigned a new action. Due: {action.due_at.strftime('%Y-%m-%d %H:%M')}",
                    notification_type="action_assigned",
                    metadata={"link": f"/actions/{action.id}/"},
                )

            messages.success(request, "Action created successfully.")
            return redirect("actions:action_detail", pk=action.id)
    else:
        # Pre-fill hospital if user has one
        initial = {}
        if user.hospital:
            initial["hospital"] = user.hospital.id

        form = ManualActionForm(request=request)

    context = {
        "form": form,
        "source_choices": ActionSource.choices,
        "status_choices": ActionStatus.choices,
    }

    return render(request, "actions/action_create.html", context)


@login_required
@require_http_methods(["POST"])
def action_create_from_ai(request, complaint_id):
    """
    Create a PX Action automatically from AI suggestion.

    Creates action in background and returns JSON response.
    Links action to the complaint automatically.
    """
    from apps.complaints.models import Complaint
    import json

    complaint = get_object_or_404(Complaint, id=complaint_id)

    # Check permission
    user = request.user
    if not (user.is_px_admin() or user.is_hospital_admin() or user.is_px_management()):
        return JsonResponse({"success": False, "error": "You do not have permission to create actions."}, status=403)

    # Get action data from POST
    action_text = request.POST.get("action", "")
    priority = request.POST.get("priority", "medium")
    category = request.POST.get("category", "process_improvement")

    if not action_text:
        return JsonResponse({"success": False, "error": "Action description is required."}, status=400)

    try:
        # Map priority/severity
        priority_map = {"high": "high", "medium": "medium", "low": "low"}

        # Create action
        action = PXAction.objects.create(
            source_type="complaint",
            content_type=ContentType.objects.get_for_model(Complaint),
            object_id=complaint.id,
            title=f"AI Suggested Action - {complaint.reference_number}",
            description=action_text,
            hospital=complaint.hospital,
            department=complaint.department,
            category=category,
            priority=priority_map.get(priority, "medium"),
            severity=priority_map.get(priority, "medium"),
            status=ActionStatus.OPEN,
            assigned_to=complaint.assigned_to,  # Assign to same person as complaint
            assigned_at=timezone.now() if complaint.assigned_to else None,
        )

        # Set due date based on priority (SLA)
        from datetime import timedelta

        due_days = {"high": 3, "medium": 7, "low": 14}
        action.due_at = timezone.now() + timedelta(days=due_days.get(priority, 7))
        action.save()

        # Create log
        PXActionLog.objects.create(
            action=action,
            log_type="status_change",
            message=f"Action created automatically from AI suggestion for complaint {complaint.reference_number}",
        )

        # Audit log
        AuditService.log_event(
            event_type="action_created",
            description=f"Action created automatically from AI suggestion",
            user=user,
            content_object=action,
            metadata={
                "complaint_id": str(complaint.id),
                "complaint_reference": complaint.reference_number,
                "source": "ai_suggestion",
            },
        )

        # Notify assigned user
        if action.assigned_to:
            from apps.notifications.services import NotificationService

            NotificationService.send_notification(
                recipient=action.assigned_to,
                title=f"New Action from AI: {action.title}",
                message=f"AI suggested a new action for complaint {complaint.reference_number}. Due: {action.due_at.strftime('%Y-%m-%d')}",
                notification_type="action_assigned",
                metadata={"link": f"/actions/{action.id}/"},
            )

        return JsonResponse(
            {
                "success": True,
                "action_id": str(action.id),
                "action_url": f"/actions/{action.id}/",
                "message": "PX Action created successfully from AI suggestion.",
            }
        )

    except Exception as e:
        return JsonResponse({"success": False, "error": str(e)}, status=500)


@login_required
@require_http_methods(["POST"])
def action_create_from_observation_ai(request, observation_id):
    """
    Create a PX Action automatically from an observation's AI suggestion.

    Creates action in background and returns JSON response.
    Links action to the observation automatically.
    """
    from apps.observations.models import Observation

    observation = get_object_or_404(Observation, id=observation_id)

    user = request.user
    if not (user.is_px_admin() or user.is_hospital_admin() or user.is_px_management()):
        return JsonResponse({"success": False, "error": "You do not have permission to create actions."}, status=403)

    action_text = request.POST.get("action", "")
    priority = request.POST.get("priority", "medium")
    category = request.POST.get("category", "process_improvement")

    if not action_text:
        return JsonResponse({"success": False, "error": "Action description is required."}, status=400)

    try:
        priority_map = {"high": "high", "medium": "medium", "low": "low"}

        action = PXAction.objects.create(
            source_type="observation",
            content_type=ContentType.objects.get_for_model(Observation),
            object_id=observation.id,
            title=f"AI Suggested Action - {observation.tracking_code}",
            description=action_text,
            hospital=observation.hospital,
            department=observation.assigned_department,
            category=category,
            priority=priority_map.get(priority, "medium"),
            severity=priority_map.get(priority, "medium"),
            status=ActionStatus.OPEN,
            assigned_to=observation.assigned_to,
            assigned_at=timezone.now() if observation.assigned_to else None,
        )

        from datetime import timedelta

        due_days = {"high": 3, "medium": 7, "low": 14}
        action.due_at = timezone.now() + timedelta(days=due_days.get(priority, 7))
        action.save()

        PXActionLog.objects.create(
            action=action,
            log_type="status_change",
            message=f"Action created automatically from AI suggestion for observation {observation.tracking_code}",
        )

        AuditService.log_event(
            event_type="action_created",
            description=f"Action created automatically from observation AI suggestion",
            user=user,
            content_object=action,
            metadata={
                "observation_id": str(observation.id),
                "observation_tracking_code": observation.tracking_code,
                "source": "ai_suggestion",
            },
        )

        # Link action to observation
        observation.action_id = action.id
        observation.save(update_fields=["action_id"])

        if action.assigned_to:
            from apps.notifications.services import NotificationService

            NotificationService.send_notification(
                recipient=action.assigned_to,
                title=f"New Action from AI: {action.title}",
                message=f"AI suggested a new action for observation {observation.tracking_code}. Due: {action.due_at.strftime('%Y-%m-%d')}",
                notification_type="action_assigned",
                metadata={"link": f"/actions/{action.id}/"},
            )

        return JsonResponse(
            {
                "success": True,
                "action_id": str(action.id),
                "action_url": f"/actions/{action.id}/",
                "message": "PX Action created successfully from observation AI suggestion.",
            }
        )

    except Exception as e:
        return JsonResponse({"success": False, "error": str(e)}, status=500)
