"""
Observations views - Public and internal views for observation management.

Public views (no login required):
- observation_create_public: Submit new observation
- observation_submitted: Success page with tracking code
- observation_track: Track observation by code

Internal views (login required):
- observation_list: List all observations with filters
- observation_detail: View observation details
- observation_triage: Triage observation
- observation_change_status: Change observation status
- observation_add_note: Add internal note
- observation_convert_to_action: Convert to PX Action
- category_list: Manage categories
- category_create/edit/delete: Category CRUD
"""

import logging

from django.contrib import messages
from django.contrib.auth.decorators import login_required, permission_required
from django.core.paginator import Paginator
from django.db.models import Q
from django.http import HttpResponseForbidden, JsonResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.utils import timezone
from django.utils.translation import gettext as _
from django.views.decorators.http import require_http_methods

from apps.accounts.models import User
from apps.accounts.services import StaffActivityService
from apps.organizations.models import Department

from .forms import (
    ConvertToActionForm,
    ObservationCategoryForm,
    ObservationDepartmentResponseForm,
    ObservationInternalForm,
    ObservationNoteForm,
    ObservationPublicForm,
    ObservationSendToDepartmentForm,
    ObservationStatusForm,
    ObservationTrackForm,
    ObservationTriageForm,
)
from .models import (
    Observation,
    ObservationAttachment,
    ObservationCategory,
    ObservationNote,
    ObservationStatus,
    ObservationStatusLog,
    VALID_OBSERVATION_TRANSITIONS,
)
from .services import ObservationService

logger = logging.getLogger(__name__)


def _format_duration(start, end):
    """Format duration between two datetimes as a human-readable string."""
    if not start or not end:
        return None
    duration = end - start
    total_seconds = int(duration.total_seconds())
    if total_seconds < 60:
        return "1m"
    days = total_seconds // 86400
    hours = (total_seconds % 86400) // 3600
    minutes = (total_seconds % 3600) // 60
    parts = []
    if days > 0:
        parts.append(f"{days}d")
    if hours > 0:
        parts.append(f"{hours}h")
    if minutes > 0 and days == 0:
        parts.append(f"{minutes}m")
    return " ".join(parts) if parts else "1m"


def _build_observation_stage_timeline(observation):
    """Build stage timeline with timestamps and durations for an observation."""
    from .models import ObservationStatusLog

    stages = []

    status_logs = list(
        ObservationStatusLog.objects.filter(
            observation=observation,
        ).select_related("changed_by").order_by("created_at")
    )

    def _find_log(to_status=None):
        for log in status_logs:
            if to_status and log.to_status != to_status:
                continue
            return log
        return None

    def _user_name(user):
        return user.get_full_name() if user else None

    if observation.created_at:
        performed_by = _user_name(observation.created_by) if hasattr(observation, 'created_by') and observation.created_by else str(_("Patient"))
        stages.append({"label": _("Created"), "timestamp": observation.created_at, "color": "bg-slate-400", "icon": "plus-circle", "performed_by": performed_by})

    if observation.triaged_at:
        performed_by = _user_name(observation.triaged_by) if hasattr(observation, 'triaged_by') else None
        stages.append({"label": _("Triaged"), "timestamp": observation.triaged_at, "color": "bg-indigo-500", "icon": "filter", "performed_by": performed_by})

    if observation.activated_at:
        activate_log = _find_log(to_status="in_progress")
        performed_by = _user_name(activate_log.changed_by) if activate_log else None
        stages.append({"label": _("Activated"), "timestamp": observation.activated_at, "color": "bg-blue-500", "icon": "play-circle", "performed_by": performed_by})

    if observation.forwarded_to_dept_at:
        stages.append({"label": _("Forwarded to Department"), "timestamp": observation.forwarded_to_dept_at, "color": "bg-purple-500", "icon": "send"})

    if observation.escalated_at:
        stages.append({"label": _("Escalated"), "timestamp": observation.escalated_at, "color": "bg-red-500", "icon": "alert-triangle"})

    if observation.dept_response_escalated_at:
        stages.append({"label": _("Dept Response Escalated"), "timestamp": observation.dept_response_escalated_at, "color": "bg-rose-600", "icon": "shield-alert"})

    if observation.department_responded_at:
        performed_by = _user_name(observation.department_responded_by) if hasattr(observation, 'department_responded_by') else None
        stages.append({"label": _("Department Responded"), "timestamp": observation.department_responded_at, "color": "bg-amber-500", "icon": "message-square", "performed_by": performed_by})

    if observation.resolved_at:
        performed_by = _user_name(observation.resolved_by) if hasattr(observation, 'resolved_by') else None
        if not performed_by:
            resolved_log = _find_log(to_status="resolved")
            performed_by = _user_name(resolved_log.changed_by) if resolved_log else None
        stages.append({"label": _("Resolved"), "timestamp": observation.resolved_at, "color": "bg-green-500", "icon": "check-circle", "performed_by": performed_by})

    if observation.closed_at:
        performed_by = _user_name(observation.closed_by) if hasattr(observation, 'closed_by') else None
        if not performed_by:
            closed_log = _find_log(to_status="closed")
            performed_by = _user_name(closed_log.changed_by) if closed_log else None
        stages.append({"label": _("Closed"), "timestamp": observation.closed_at, "color": "bg-emerald-600", "icon": "circle-check", "performed_by": performed_by})

    stages.sort(key=lambda s: s["timestamp"])

    for i, stage in enumerate(stages):
        stage["duration_from_prev"] = _format_duration(stages[i - 1]["timestamp"], stage["timestamp"]) if i > 0 else None

    total_time = None
    if len(stages) >= 2:
        total_time = _format_duration(stages[0]["timestamp"], stages[-1]["timestamp"])

    return {"stages": stages, "total_time": total_time}


# =============================================================================
# PUBLIC VIEWS (No Login Required)
# =============================================================================


def observation_create_public(request):
    """
    Public view for submitting observations.

    No login required - anonymous submissions allowed.
    """
    if request.method == "POST":
        form = ObservationPublicForm(request.POST, request.FILES)

        if form.is_valid():
            try:
                client_ip = get_client_ip(request)
                user_agent = request.META.get("HTTP_USER_AGENT", "")
                attachments = request.FILES.getlist("attachments")

                hospital_id = request.POST.get("hospital")
                hospital = None
                if hospital_id:
                    try:
                        from apps.organizations.models import Hospital
                        hospital = Hospital.objects.get(id=hospital_id)
                    except Exception:
                        pass

                observation = ObservationService.create_observation(
                    description=form.cleaned_data["description"],
                    severity=form.cleaned_data.get("severity", "medium"),
                    category=None,
                    title=form.cleaned_data.get("title", ""),
                    location_text=form.cleaned_data.get("location_text", ""),
                    location_type=form.cleaned_data.get("location_type", ""),
                    incident_datetime=form.cleaned_data.get("incident_datetime"),
                    reporter_staff_id=form.cleaned_data.get("reporter_staff_id", ""),
                    reporter_name=form.cleaned_data.get("reporter_name", ""),
                    reporter_phone=form.cleaned_data.get("reporter_phone", ""),
                    reporter_email=form.cleaned_data.get("reporter_email", ""),
                    client_ip=client_ip,
                    user_agent=user_agent,
                    attachments=attachments,
                    hospital=hospital,
                    area=form.cleaned_data.get("area"),
                    section=form.cleaned_data.get("section"),
                    source_legacy="public_form",
                )

                return redirect("observations:observation_submitted", tracking_code=observation.tracking_code)

            except Exception as e:
                logger.error(f"Error creating observation: {e}")
                messages.error(request, "An error occurred while submitting your observation. Please try again.")
    else:
        form = ObservationPublicForm()

    from apps.organizations.models import Hospital

    context = {
        "form": form,
        "hospitals": Hospital.objects.filter(status="active").order_by("name"),
    }

    return render(request, "observations/public_new.html", context)


def observation_submitted(request, tracking_code):
    """
    Success page after observation submission.

    Shows tracking code for future reference.
    """
    observation = get_object_or_404(Observation, tracking_code=tracking_code)

    context = {
        "observation": observation,
        "tracking_code": tracking_code,
    }

    return render(request, "observations/public_success.html", context)


def observation_track(request):
    """
    Public view to track observation status by tracking code.

    Shows minimal status information only (no internal notes).
    """
    observation = None
    error_message = None
    tracking_code = request.GET.get("tracking_code", "").strip()

    if request.method == "POST":
        tracking_code = request.POST.get("tracking_code", "").strip()
        if not tracking_code:
            error_message = _("Please enter a tracking code.")
        else:
            try:
                observation = (
                    Observation.objects.select_related("category", "hospital")
                    .prefetch_related("status_logs", "notes")
                    .get(tracking_code__iexact=tracking_code)
                )
            except Observation.DoesNotExist:
                error_message = _("No observation found with this tracking code. Please check and try again.")
    elif tracking_code:
        try:
            observation = (
                Observation.objects.select_related("category", "hospital")
                .prefetch_related("status_logs", "notes")
                .get(tracking_code__iexact=tracking_code)
            )
        except Observation.DoesNotExist:
            error_message = _("No observation found with this tracking code. Please check and try again.")

    has_response = False
    response_en = ""
    response_ar = ""
    if observation:
        has_response = bool(observation.department_response_en or observation.department_response_ar)
        response_en = observation.department_response_en or ""
        response_ar = observation.department_response_ar or ""

    context = {
        "observation": observation,
        "error_message": error_message,
        "tracking_code": tracking_code,
        "has_response": has_response,
        "response_en": response_en,
        "response_ar": response_ar,
    }

    return render(request, "observations/public_track.html", context)


# =============================================================================
# INTERNAL VIEWS (Login Required)
# =============================================================================


@login_required
@require_http_methods(["GET", "POST"])
def observation_create(request):
    """
    Internal view for authenticated staff to create observations.
    """
    communication_request = None
    if request.method == "POST":
        form = ObservationInternalForm(request.POST, request=request)

        if form.is_valid():
            try:
                client_ip = get_client_ip(request)
                user_agent = request.META.get("HTTP_USER_AGENT", "")
                user = request.user

                observation = ObservationService.create_observation(
                    description=form.cleaned_data["description"],
                    severity=form.cleaned_data.get("severity") or request.POST.get("severity", "medium"),
                    category=None,
                    title="",
                    location_text="",
                    incident_datetime=form.cleaned_data.get("incident_datetime"),
                    reporter_staff_id=user.employee_id or "",
                    reporter_name=user.get_full_name(),
                    reporter_phone="",
                    reporter_email=user.email,
                    client_ip=client_ip,
                    user_agent=user_agent,
                    hospital=form.cleaned_data.get("hospital") or (user.hospital if hasattr(user, 'hospital') else None),
                    assigned_department=form.cleaned_data.get("assigned_department"),
                    source=form.cleaned_data.get("px_source"),
                    source_legacy="staff_portal",
                )

                assigned_dept = form.cleaned_data.get("assigned_department")
                assigned_user = form.cleaned_data.get("assigned_to")
                section = form.cleaned_data.get("section")
                if assigned_dept:
                    observation.assigned_department = assigned_dept
                if assigned_user:
                    observation.assigned_to = assigned_user
                    observation.status = ObservationStatus.IN_PROGRESS
                    ObservationStatusLog.objects.create(
                        observation=observation,
                        from_status=ObservationStatus.OPEN,
                        to_status=ObservationStatus.IN_PROGRESS,
                        comment="Auto-assigned during creation",
                    )
                if section:
                    observation.section = section
                observation.save()

                comm_req_id = request.POST.get("comm_req")
                if comm_req_id:
                    try:
                        from apps.px_sources.models import CommunicationRequest
                        cr = CommunicationRequest.objects.get(pk=comm_req_id)
                        cr.link_to_record(observation)
                    except Exception:
                        pass

                StaffActivityService.log_from_request(
                    request,
                    activity_type="create",
                    description=f"Created observation {observation.tracking_code}",
                    content_object=observation,
                    module="observations",
                )

                messages.success(request, f"Observation {observation.tracking_code} created successfully.")
                return redirect("observations:observation_detail", pk=observation.id)

            except Exception as e:
                logger.error(f"Error creating observation: {e}")
                messages.error(request, "An error occurred while creating the observation. Please try again.")
    else:
        communication_request = None
        comm_req_id = request.GET.get("comm_req")
        initial_data = {}
        if comm_req_id:
            try:
                from apps.px_sources.models import CommunicationRequest
                cr_data = CommunicationRequest.get_initial_data(comm_req_id)
                communication_request = cr_data["communication_request"]
                for key in ("patient_file_number", "description"):
                    if key in cr_data["initial"] and cr_data["initial"][key]:
                        initial_data[key] = cr_data["initial"][key]
            except Exception:
                pass

        form = ObservationInternalForm(request=request, initial=initial_data)

    context = {
        "form": form,
        "communication_request": communication_request,
    }

    return render(request, "observations/observation_create.html", context)


@login_required
def observation_list(request):
    """
    Internal view for listing observations with filters.

    Features:
    - Server-side pagination
    - Advanced filters (status, severity, category, department, etc.)
    - Search by tracking code, description
    - RBAC filtering
    """
    # Base queryset with optimizations
    queryset = Observation.objects.select_related(
        "category", "assigned_department", "assigned_to", "triaged_by", "resolved_by", "closed_by"
    )

    # 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(
                Q(assigned_department__hospital=selected_hospital) | Q(assigned_department__isnull=True)
            )
    elif user.is_hospital_admin() and user.hospital:
        queryset = queryset.filter(Q(assigned_department__hospital=user.hospital) | Q(assigned_department__isnull=True))
    elif user.is_department_manager() and user.department:
        queryset = queryset.filter(assigned_department=user.department)
    elif user.hospital:
        queryset = queryset.filter(Q(assigned_department__hospital=user.hospital) | Q(assigned_department__isnull=True))

    # 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)

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

    department_filter = request.GET.get("assigned_department")
    if department_filter:
        queryset = queryset.filter(assigned_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)

    is_anonymous_filter = request.GET.get("is_anonymous")
    if is_anonymous_filter == "yes":
        queryset = queryset.filter(reporter_staff_id="", reporter_name="")
    elif is_anonymous_filter == "no":
        queryset = queryset.exclude(reporter_staff_id="", reporter_name="")

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

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

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

    ALLOWED_ORDER_BY = {"-created_at", "created_at", "-updated_at", "updated_at", "severity", "-severity"}
    order_by = request.GET.get("order_by", "-created_at")
    if order_by not in ALLOWED_ORDER_BY:
        order_by = "-created_at"
    queryset = queryset.order_by(order_by)

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

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

    from apps.core.utils import get_assignable_users
    assignable_users = get_assignable_users(user.hospital)

    categories = ObservationCategory.objects.filter(is_active=True)

    stats = ObservationService.get_statistics(
        hospital=selected_hospital or (user.hospital if not user.is_px_admin() else None),
        department=user.department if user.is_department_manager() else None,
    )

    context = {
        "page_obj": page_obj,
        "observations": page_obj.object_list,
        "stats": stats,
        "departments": departments,
        "assignable_users": assignable_users,
        "categories": categories,
        "status_choices": ObservationStatus.choices,
        "filters": request.GET,
    }

    return render(request, "observations/observation_list.html", context)


@login_required
def observation_detail(request, pk):
    """
    Internal view for observation details.

    Features:
    - Full observation details
    - Timeline (status logs + notes)
    - Attachments
    - Linked PX Action
    - Workflow actions
    """
    observation = get_object_or_404(
        Observation.objects.select_related(
            "category", "assigned_department", "assigned_to", "triaged_by", "resolved_by", "closed_by",
            "legacy_location", "legacy_main_section", "legacy_subsection", "hospital",
            "taxonomy_domain", "taxonomy_category", "taxonomy_subcategory", "taxonomy_classification",
        ).prefetch_related("attachments", "observation_notes__created_by", "status_logs__changed_by"),
        pk=pk,
    )

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

    # Get timeline (combine status logs and notes)
    status_logs = list(observation.status_logs.all())
    notes = list(observation.observation_notes.all())

    timeline = []
    for log in status_logs:
        timeline.append(
            {
                "type": "status_change",
                "created_at": log.created_at,
                "item": log,
            }
        )
    for note in notes:
        timeline.append(
            {
                "type": "note",
                "created_at": note.created_at,
                "item": note,
            }
        )
    timeline.sort(key=lambda x: x["created_at"], reverse=True)
    stage_timeline = _build_observation_stage_timeline(observation)

    # Get attachments
    attachments = observation.attachments.all()

    # Get linked PX Action if exists
    px_action = None
    if observation.action_id:
        from apps.px_action_center.models import PXAction

        try:
            px_action = PXAction.objects.get(id=observation.action_id)
        except PXAction.DoesNotExist:
            pass

    # Get assignable users and departments
    departments = Department.objects.filter(status="active")
    from apps.core.utils import get_assignable_users
    assignable_users = get_assignable_users(user.hospital)
    if user.hospital:
        departments = departments.filter(hospital=user.hospital)

    # Forms
    triage_form = ObservationTriageForm(
        initial={
            "assigned_department": observation.assigned_department,
            "assigned_to": observation.assigned_to,
            "status": observation.status,
        },
        hospital=user.hospital,
    )
    status_form = ObservationStatusForm(initial={"status": observation.status})
    note_form = ObservationNoteForm()

    from apps.rca.models import RootCauseAnalysis as RCA
    from django.contrib.contenttypes.models import ContentType as CT

    observation_ct = CT.objects.get_for_model(Observation)
    linked_rcas = RCA.objects.filter(
        content_type=observation_ct, object_id=observation.pk, is_deleted=False
    ).select_related("assigned_to", "created_by")

    context = {
        "observation": observation,
        "timeline": timeline,
        "stage_timeline": stage_timeline,
        "attachments": attachments,
        "px_action": px_action,
        "departments": departments,
        "assignable_users": assignable_users,
        "triage_form": triage_form,
        "status_form": status_form,
        "note_form": note_form,
        "status_choices": ObservationStatus.choices,
        "can_triage": user.has_perm("observations.triage_observation") or user.is_px_admin(),
        "can_convert": user.is_px_admin() or user.is_hospital_admin(),
        "can_send_to_department": user.is_px_admin() or user.is_hospital_admin() or user.is_department_manager() or user.is_px_management(),
        "can_respond_to_department": user.is_px_admin() or user.is_hospital_admin() or (user.is_champion() and observation.assigned_department == user.department),
        "can_review_dept_response": user.is_px_admin() or user.is_hospital_admin(),
        "can_send_reminder": user.is_px_admin() or user.is_hospital_admin(),
        "can_delete": user.is_px_admin() or user.is_hospital_admin(),
        "linked_rcas": linked_rcas,
    }

    from django.contrib.contenttypes.models import ContentType
    obs_ct = ContentType.objects.get_for_model(observation)
    context["content_type_id"] = obs_ct.pk
    context["object_id"] = observation.pk
    generic_notes = observation.notes.select_related("created_by").all()
    context["generic_notes"] = generic_notes
    context["generic_notes_count"] = generic_notes.count()

    escalation_targets = []
    escalation_email_subject = ""
    escalation_email_body = ""

    if observation.assigned_department:
        from apps.organizations.models import Staff as OrgStaff

        dept = observation.assigned_department
        dept_holders = [
            h for h in dept.get_role_holders()
            if h["staff"].user and h["staff"].user.is_active
        ]
        escalation_targets.extend(dept_holders)

        hospital_admins = OrgStaff.objects.filter(
            user__is_active=True,
            user__groups__name__in=["Hospital Admin", "Department Manager"],
        )
        if observation.hospital:
            hospital_admins = hospital_admins.filter(department__hospital=observation.hospital)
        for admin in hospital_admins.select_related("user"):
            escalation_targets.append({
                "staff": admin,
                "staff_id": str(admin.id),
                "name": admin.get_full_name(),
                "email": admin.email or (admin.user.email if admin.user else None),
                "role_field": "hospital_admin",
                "role_label": "Hospital Admin" if admin.user.groups.filter(name="Hospital Admin").exists() else "Department Manager",
            })

        dept_name = dept.get_localized_name()
        escalation_email_subject = f"Observation Escalation - {observation.tracking_code} - {dept_name}"
        escalation_email_body = (
            f"Dear Team,\n\n"
            f"This is to escalate observation {observation.tracking_code} regarding the {dept_name} department.\n\n"
            f"Severity: {observation.get_severity_display()}\n"
            f"Status: {observation.get_status_display()}\n"
            f"Description: {observation.description[:500]}\n\n"
            f"Please review and take appropriate action.\n\n"
            f"Thank you."
        )

    context["escalation_targets"] = escalation_targets
    context["escalation_email_subject"] = escalation_email_subject
    context["escalation_email_body"] = escalation_email_body

    return render(request, "observations/observation_detail.html", context)


@login_required
@require_http_methods(["POST"])
def observation_triage(request, pk):
    """
    Triage an observation - assign department/owner and update status.
    """
    observation = get_object_or_404(Observation, pk=pk)

    # Check permission
    user = request.user
    if not (user.has_perm("observations.triage_observation") or user.is_px_admin()):
        messages.error(request, "You don't have permission to triage observations.")
        return redirect("observations:observation_detail", pk=pk)

    form = ObservationTriageForm(request.POST, hospital=user.hospital)

    if form.is_valid():
        try:
            ObservationService.triage_observation(
                observation=observation,
                triaged_by=user,
                assigned_department=form.cleaned_data.get("assigned_department"),
                assigned_to=form.cleaned_data.get("assigned_to"),
                new_status=form.cleaned_data.get("status"),
                note=form.cleaned_data.get("note", ""),
            )
            messages.success(request, "Observation triaged successfully.")
        except Exception as e:
            logger.error(f"Error triaging observation: {e}")
            messages.error(request, f"Error triaging observation: {str(e)}")
    else:
        messages.error(request, "Invalid form data.")

    return redirect("observations:observation_detail", pk=pk)


@login_required
@require_http_methods(["POST"])
def observation_change_status(request, pk):
    """
    Change observation status.
    """
    observation = get_object_or_404(Observation, pk=pk)

    # Check permission
    user = request.user
    if not (user.has_perm("observations.triage_observation") or user.is_px_admin()):
        messages.error(request, "You don't have permission to change observation status.")
        return redirect("observations:observation_detail", pk=pk)

    form = ObservationStatusForm(request.POST)

    if form.is_valid():
        try:
            ObservationService.change_status(
                observation=observation,
                new_status=form.cleaned_data["status"],
                changed_by=user,
                comment=form.cleaned_data.get("comment", ""),
            )
            messages.success(request, f"Status changed to {form.cleaned_data['status']}.")
        except Exception as e:
            logger.error(f"Error changing status: {e}")
            messages.error(request, f"Error changing status: {str(e)}")
    else:
        messages.error(request, "Invalid form data.")

    return redirect("observations:observation_detail", pk=pk)


@login_required
@require_http_methods(["POST"])
def observation_assign(request, pk):
    observation = get_object_or_404(Observation, pk=pk)

    user = request.user
    if not (user.is_px_admin() or user.is_hospital_admin()):
        messages.error(request, "You don't have permission to assign observations.")
        return redirect("observations:observation_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("observations:observation_detail", pk=pk)

    try:
        assignee = User.objects.get(id=user_id)
        old_assignee = observation.assigned_to
        old_status = observation.status

        observation.assigned_to = assignee
        observation.assigned_at = timezone.now()

        reopened = False
        new_status = old_status
        if old_status in ("resolved", "closed"):
            new_status = ObservationStatus.IN_PROGRESS
            observation.resolved_at = None
            observation.resolved_by = None
            observation.closed_at = None
            observation.closed_by = None
            reopened = True
        elif old_status == ObservationStatus.OPEN:
            new_status = ObservationStatus.IN_PROGRESS

        observation.save()

        ObservationService.change_status(
            observation=observation,
            new_status=new_status,
            changed_by=request.user,
            comment=f"{'Reopened and a' if reopened else 'A'}ssigned to {assignee.get_full_name()}"
            + (f" (reassigned from {old_assignee.get_full_name()})" if old_assignee else ""),
        )

        messages.success(request, f"Observation {'reopened and ' if reopened else ''}assigned to {assignee.get_full_name()}.")
    except User.DoesNotExist:
        messages.error(request, "User not found.")

    return redirect("observations:observation_detail", pk=pk)


@login_required
@require_http_methods(["POST"])
def observation_activate(request, pk):
    """Activate observation and assign to current user."""
    observation = get_object_or_404(Observation, pk=pk)
    user = request.user

    if not (user.is_px_admin() or user.is_hospital_admin()):
        messages.error(request, _("You don't have permission to activate observations."))
        return redirect("observations:observation_detail", pk=pk)

    if observation.assigned_to == user:
        messages.info(request, _("This observation is already assigned to you."))
        return redirect("observations:observation_detail", pk=pk)

    old_assignee = observation.assigned_to
    old_status = observation.status

    observation.assigned_to = user
    observation.assigned_at = timezone.now()
    observation.save(update_fields=["assigned_to", "assigned_at"])

    if old_status == ObservationStatus.OPEN:
        ObservationService.change_status(
            observation=observation,
            new_status=ObservationStatus.IN_PROGRESS,
            changed_by=user,
            comment=f"Observation activated and assigned to {user.get_full_name()}"
            + (f" (reassigned from {old_assignee.get_full_name()})" if old_assignee else ""),
        )
    else:
        ObservationNote.objects.create(
            observation=observation,
            note=f"Observation reassigned to {user.get_full_name()}"
            + (f" (reassigned from {old_assignee.get_full_name()})" if old_assignee else ""),
            created_by=user,
            is_internal=True,
        )

    StaffActivityService.log_from_request(
        request,
        activity_type="update",
        description=f"Activated observation {observation.tracking_code or observation.id}",
        content_object=observation,
        module="observations",
    )

    messages.success(request, _("Observation activated and assigned to you successfully."))
    return redirect("observations:observation_detail", pk=pk)


@login_required
@require_http_methods(["POST"])
def observation_reopen(request, pk):
    observation = get_object_or_404(Observation, pk=pk)

    user = request.user
    if not (user.is_px_admin() or user.is_hospital_admin()):
        messages.error(request, "You don't have permission to reopen observations.")
        return redirect("observations:observation_detail", pk=pk)

    if observation.status not in ("resolved", "closed"):
        messages.error(request, "Only resolved or closed observations can be reopened.")
        return redirect("observations:observation_detail", pk=pk)

    old_status = observation.status
    note_text = request.POST.get("note", "Observation reopened")

    ObservationService.change_status(
        observation=observation,
        new_status=ObservationStatus.IN_PROGRESS,
        changed_by=user,
        comment=note_text,
    )

    observation.resolved_at = None
    observation.resolved_by = None
    observation.closed_at = None
    observation.closed_by = None
    observation.save(update_fields=["resolved_at", "resolved_by", "closed_at", "closed_by"])

    messages.success(request, "Observation reopened successfully.")
    return redirect("observations:observation_detail", pk=pk)


@login_required
@require_http_methods(["POST"])
def observation_add_note(request, pk):
    """
    Add internal note to observation.
    """
    observation = get_object_or_404(Observation, pk=pk)

    form = ObservationNoteForm(request.POST)

    if form.is_valid():
        try:
            ObservationService.add_note(
                observation=observation,
                note=form.cleaned_data["note"],
                created_by=request.user,
                is_internal=form.cleaned_data.get("is_internal", True),
            )
            messages.success(request, "Note added successfully.")
        except Exception as e:
            logger.error(f"Error adding note: {e}")
            messages.error(request, f"Error adding note: {str(e)}")
    else:
        messages.error(request, "Please enter a note.")

    return redirect("observations:observation_detail", pk=pk)


@login_required
@require_http_methods(["GET", "POST"])
def observation_convert_to_action(request, pk):
    """
    Convert observation to PX Action.
    """
    observation = get_object_or_404(Observation, 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 convert observations to actions.")
        return redirect("observations:observation_detail", pk=pk)

    # Check if already converted
    if observation.action_id:
        messages.warning(request, "This observation has already been converted to an action.")
        return redirect("observations:observation_detail", pk=pk)

    if request.method == "POST":
        form = ConvertToActionForm(request.POST)

        if form.is_valid():
            try:
                action = ObservationService.convert_to_action(
                    observation=observation,
                    created_by=user,
                    title=form.cleaned_data["title"],
                    description=form.cleaned_data["description"],
                    category=form.cleaned_data["category"],
                    priority=form.cleaned_data["priority"],
                    assigned_department=form.cleaned_data.get("assigned_department"),
                    assigned_to=form.cleaned_data.get("assigned_to"),
                )
                messages.success(request, f"Observation converted to action successfully.")
                return redirect("observations:observation_detail", pk=pk)
            except Exception as e:
                logger.error(f"Error converting to action: {e}")
                messages.error(request, f"Error converting to action: {str(e)}")
    else:
        # Pre-populate form
        initial = {
            "title": f"Observation {observation.tracking_code}",
            "description": observation.description,
            "priority": observation.severity,
            "assigned_department": observation.assigned_department,
            "assigned_to": observation.assigned_to,
        }
        if observation.title:
            initial["title"] += f" - {observation.title}"
        elif observation.category:
            initial["title"] += f" - {observation.category.name_en}"

        form = ConvertToActionForm(initial=initial)

    context = {
        "observation": observation,
        "form": form,
    }

    return render(request, "observations/convert_to_action.html", context)


@login_required
@require_http_methods(["POST"])
def observation_send_to_department(request, pk):
    """
    Send an observation to a department for response.
    """
    observation = get_object_or_404(Observation, pk=pk)

    user = request.user
    if not (
        user.is_px_admin()
        or user.is_hospital_admin()
        or user.is_department_manager()
        or user.is_px_management()
    ):
        messages.error(request, _("You don't have permission to send observations to departments."))
        return redirect("observations:observation_detail", pk=pk)

    department_id = request.POST.get("department_id")
    if not department_id:
        messages.error(request, _("Please select a department."))
        return redirect("observations:observation_detail", pk=pk)

    from apps.organizations.models import Department
    try:
        department = Department.objects.select_related("champion", "manager").get(pk=department_id, status="active")
    except Department.DoesNotExist:
        messages.error(request, _("Department not found."))
        return redirect("observations:observation_detail", pk=pk)

    if not department.champion and not department.manager:
        messages.error(request, _(f"Cannot send to {department.get_localized_name()}. This department has no champion or manager assigned."))
        return redirect("observations:observation_detail", pk=pk)

    contact_person_id = request.POST.get("contact_person_id")
    if not contact_person_id:
        messages.error(request, _("Please select a contact person."))
        return redirect("observations:observation_detail", pk=pk)

    contact_info = department.is_valid_contact_person(contact_person_id)
    if not contact_info:
        messages.error(request, _("Selected person is not a role holder in this department."))
        return redirect("observations:observation_detail", pk=pk)

    contact_person = contact_info["staff"]

    note_en = request.POST.get("note_en", "").strip()
    note_ar = request.POST.get("note_ar", "").strip()
    recipient_type = request.POST.get("recipient_type", "staff")

    note_parts = []
    if note_en:
        note_parts.append(note_en)
    if note_ar:
        note_parts.append(note_ar)
    combined_note = "\n\n".join(note_parts)

    # Use assigned_department as the outgoing department (reusing existing field)
    observation.assigned_department = department
    observation.forwarded_to_dept_at = timezone.now()
    observation.sent_to_department = True
    observation.sent_to_department_at = timezone.now()

    sla_config = observation.get_sla_config()
    if sla_config and sla_config.dept_response_hours:
        from datetime import timedelta
        observation.dept_response_sla_due_at = timezone.now() + timedelta(hours=sla_config.dept_response_hours)
        observation.dept_response_is_overdue = False
        observation.dept_response_reminder_sent_at = None
        observation.dept_response_second_reminder_sent_at = None
        observation.dept_response_escalated_at = None

    old_status = observation.status
    observation.contact_status = "contacted"
    observation.contact_status_at = timezone.now()
    observation.contact_status_by = user
    observation.save()

    # Create note
    ObservationNote.objects.create(
        observation=observation,
        note=combined_note or f"Sent to {department.get_localized_name()} for response",
        created_by=user,
        is_internal=True,
    )

    try:
        import secrets
        from apps.notifications.settings_service import NotificationServiceWithSettings

        # Generate token for response link
        response_token = secrets.token_urlsafe(32)
        observation.response_token = response_token
        observation.response_token_sent_at = timezone.now()
        observation.save(update_fields=["response_token", "response_token_sent_at"])

        # Build response link
        from django.contrib.sites.shortcuts import get_current_site
        current_site = get_current_site(request)
        domain = current_site.domain if current_site else request.get_host()
        response_link = f"https://{domain}/observations/{observation.pk}/respond/{response_token}/"

        NotificationServiceWithSettings.send_observation_department_assigned(
            department, observation, context_note_en=note_en, context_note_ar=note_ar,
            recipient_type=recipient_type,
        )

        contact_email = contact_person.email or (contact_person.user.email if contact_person.user else None)
        if contact_email:
            from apps.notifications.services import NotificationService, get_email_header_html
            NotificationService.send_email(
                email=contact_email,
                subject=f"Observation {observation.tracking_code} - Response Required",
                message=f"An observation has been sent to your department ({department.get_localized_name()}) for response.\n\nSubmit your response here: {response_link}\n\nDeadline: {observation.dept_response_sla_due_at}",
                html_message=f"""
<div style="font-family: 'Segoe UI', Tahoma, sans-serif; max-width: 600px; margin: 0 auto; border: 1px solid #e5e7eb; border-radius: 8px; overflow: hidden;">
    {get_email_header_html()}
    <div style="padding: 20px;">
        <h2 style="color: #005696; font-size: 18px; margin: 0 0 12px 0;">Observation {observation.tracking_code} - Response Required</h2>
        <p style="margin: 0 0 12px 0;">An observation has been sent to your department (<strong>{department.get_localized_name()}</strong>) for response.</p>
        <table style="width: 100%; border-collapse: collapse; margin: 0 0 12px 0;">
            <tr><td style="padding: 4px 0; color: #6b7280; width: 120px;">Tracking Code:</td><td style="padding: 4px 0;">{observation.tracking_code}</td></tr>
            <tr><td style="padding: 4px 0; color: #6b7280;">Deadline:</td><td style="padding: 4px 0;">{observation.dept_response_sla_due_at}</td></tr>
        </table>
        <div style="text-align: center; margin: 20px 0;">
            <a href="{response_link}" style="background: #005696; color: white; padding: 10px 24px; border-radius: 8px; text-decoration: none; font-weight: 600;">Submit Response</a>
        </div>
        <p style="margin: 0; color: #6b7280; font-size: 13px;">This link can only be used once. After submission, it will expire.</p>
    </div>
</div>
""",
                related_object=observation,
            )
    except Exception as e:
        logger.warning(f"Failed to send department notification: {e}")

    if recipient_type == "department_email":
        messages.success(
            request,
            _("Observation sent to %(dept)s department email.")
            % {"dept": department.get_localized_name()},
        )
    else:
        messages.success(
            request,
            _("Observation sent to %(dept)s. Department champions have been notified.")
            % {"dept": department.get_localized_name()},
        )
    return redirect("observations:observation_detail", pk=pk)


@login_required
@require_http_methods(["POST"])
def observation_escalate(request, pk):
    from apps.organizations.models import Staff
    from django.contrib import messages as django_messages

    observation = get_object_or_404(Observation, pk=pk)

    user = request.user
    if not (
        user.is_px_admin()
        or user.is_hospital_admin()
        or user.is_px_management()
    ):
        messages.error(request, _("You don't have permission to escalate observations."))
        return redirect("observations:observation_detail", pk=pk)

    if observation.status in ("closed", "cancelled", "rejected"):
        messages.error(request, _("Cannot escalate a closed, cancelled, or rejected observation."))
        return redirect("observations:observation_detail", pk=pk)

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

    escalate_to_staff = None
    escalate_to_user = None

    if escalate_to_id:
        try:
            escalate_to_staff = Staff.objects.get(id=escalate_to_id, status="active")
            if escalate_to_staff.user and escalate_to_staff.user.is_active:
                escalate_to_user = escalate_to_staff.user
        except Staff.DoesNotExist:
            pass

    if not escalate_to_user:
        messages.error(request, _("Please select a valid person to escalate to."))
        return redirect("observations:observation_detail", pk=pk)

    observation.escalated_at = timezone.now()
    observation.save(update_fields=["escalated_at"])

    ObservationStatusLog.objects.create(
        observation=observation,
        from_status=observation.status,
        to_status=observation.status,
        changed_by=user,
        comment=f"Observation escalated to {escalate_to_staff.get_full_name()}. Reason: {reason or 'N/A'}",
    )

    ObservationNote.objects.create(
        observation=observation,
        note=f"Observation escalated to {escalate_to_staff.get_full_name()}. Reason: {reason or 'N/A'}",
        created_by=user,
        is_internal=True,
    )

    email_subject = request.POST.get("email_subject", f"Observation Escalated - {observation.tracking_code}")
    email_body = request.POST.get("email_body", "")

    if escalate_to_user.email:
        try:
            from apps.notifications.services import NotificationService, get_email_header_html
            NotificationService.send_email(
                email=escalate_to_user.email,
                subject=email_subject,
                message=email_body,
                html_message=f"""
<div style="font-family: 'Segoe UI', Tahoma, sans-serif; max-width: 600px; margin: 0 auto; border: 1px solid #e5e7eb; border-radius: 8px; overflow: hidden;">
    {get_email_header_html()}
    <div style="padding: 20px;">
        <h2 style="color: #005696; font-size: 18px; margin: 0 0 12px 0;">Observation Escalated - {observation.tracking_code}</h2>
        <p style="margin: 0 0 12px 0;">An observation has been escalated to you.</p>
        <table style="width: 100%; border-collapse: collapse; margin: 0 0 12px 0;">
            <tr><td style="padding: 4px 0; color: #6b7280; width: 120px;">Tracking Code:</td><td style="padding: 4px 0;">{observation.tracking_code}</td></tr>
            <tr><td style="padding: 4px 0; color: #6b7280;">Escalated by:</td><td style="padding: 4px 0;">{user.get_full_name()}</td></tr>
            <tr><td style="padding: 4px 0; color: #6b7280;">Reason:</td><td style="padding: 4px 0;">{reason or 'N/A'}</td></tr>
        </table>
        <div style="background: #f9fafb; padding: 12px; border-radius: 6px; margin: 0 0 12px 0;">
            <p style="margin: 0;">{email_body}</p>
        </div>
    </div>
</div>
""",
                related_object=observation,
                metadata={
                    "notification_type": "observation_escalated",
                    "escalated_by": str(user.id),
                    "reason": reason,
                },
            )
        except Exception as e:
            logger.error(f"Failed to send observation escalation email: {e}")

    messages.success(request, _(f"Observation escalated to {escalate_to_staff.get_full_name()}."))
    return redirect("observations:observation_detail", pk=pk)


@login_required
@require_http_methods(["POST"])
def observation_send_to(request, pk):
    """
    Unified AJAX endpoint to send observation to either a person or department.
    """
    from django.http import JsonResponse
    from apps.notifications.services import NotificationService, get_email_header_html
    from apps.accounts.models import User

    observation = get_object_or_404(Observation, pk=pk)
    user = request.user

    # Check permission
    if not (
        user.is_px_admin()
        or user.is_hospital_admin()
        or user.is_department_manager()
        or user.is_px_management()
    ):
        return JsonResponse({
            "success": False,
            "error": str(_("You don't have permission to send this observation.")),
        }, status=403)

    recipient_type = request.POST.get("recipient_type", "department")
    note = request.POST.get("note", "").strip()

    try:
        if recipient_type == "person":
            person_id = request.POST.get("person_id")
            if not person_id:
                return JsonResponse({
                    "success": False,
                    "error": str(_("Please select a person.")),
                }, status=400)

            try:
                person = User.objects.get(id=person_id)
            except User.DoesNotExist:
                return JsonResponse({
                    "success": False,
                    "error": str(_("User not found.")),
                }, status=400)

            # Assign observation to person
            observation.assigned_to = person
            observation.assigned_at = timezone.now()
            observation.save(update_fields=["assigned_to", "assigned_at"])

            # Send notification
            if person.email:
                NotificationService.send_email(
                    email=person.email,
                    subject=f"Observation Assigned - {observation.tracking_code}",
                    message=f"You have been assigned to observation #{observation.tracking_code}.",
                    html_message=f"""
                    <div style="font-family: 'Segoe UI', Tahoma, sans-serif; max-width: 600px; margin: 0 auto; background: white; border-radius: 12px; overflow: hidden; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">
                        {get_email_header_html()}
                        <div style="padding: 30px;">
                            <p>You have been assigned to observation <strong>#{observation.tracking_code}</strong>.</p>
                            <p><strong>Title:</strong> {observation.title or 'N/A'}</p>
                            {f'<p><strong>Note:</strong> {note}</p>' if note else ''}
                            <a href="https://{request.get_host()}/observations/{observation.pk}/" style="display: inline-block; padding: 12px 24px; background: #005696; color: white; text-decoration: none; border-radius: 6px; margin: 10px 0;">View Observation</a>
                        </div>
                    </div>
                    """,
                    related_object=observation,
                )

            message = f"Observation sent to {person.get_full_name()}."

        else:  # department
            department_id = request.POST.get("department_id")
            if not department_id:
                return JsonResponse({
                    "success": False,
                    "error": str(_("Please select a department.")),
                }, status=400)

            try:
                department = Department.objects.select_related("champion", "manager").get(pk=department_id, status="active")
            except Department.DoesNotExist:
                return JsonResponse({
                    "success": False,
                    "error": str(_("Department not found.")),
                }, status=400)

            if not department.champion and not department.manager:
                return JsonResponse({
                    "success": False,
                    "error": str(_(f"Cannot send to {department.get_localized_name()}. This department has no champion or manager assigned.")),
                }, status=400)

            contact_person_id = request.POST.get("contact_person_id")
            if not contact_person_id:
                return JsonResponse({
                    "success": False,
                    "error": str(_("Please select a contact person.")),
                }, status=400)

            contact_info = department.is_valid_contact_person(contact_person_id)
            if not contact_info:
                return JsonResponse({
                    "success": False,
                    "error": str(_("Selected person is not a role holder in this department.")),
                }, status=400)

            # Send to department
            observation.assigned_department = department
            observation.forwarded_to_dept_at = timezone.now()
            observation.sent_to_department = True
            observation.sent_to_department_at = timezone.now()

            sla_config = observation.get_sla_config()
            if sla_config and sla_config.dept_response_hours:
                from datetime import timedelta
                observation.dept_response_sla_due_at = timezone.now() + timedelta(hours=sla_config.dept_response_hours)
                observation.dept_response_is_overdue = False
                observation.dept_response_reminder_sent_at = None
                observation.dept_response_second_reminder_sent_at = None
                observation.dept_response_escalated_at = None

            message = f"Observation sent to {department.get_localized_name()} — {contact_info['name']} ({contact_info['role_label']})."

        old_status_before_send = observation.status
        observation.contact_status = "contacted"
        observation.contact_status_at = timezone.now()
        observation.contact_status_by = user

        observation.save()

        ObservationNote.objects.create(
            observation=observation,
            note=note or f"Sent to {recipient_type}",
            created_by=user,
            is_internal=True,
        )

        # Send department notification if applicable
        if recipient_type == "department":
            try:
                from apps.notifications.settings_service import NotificationServiceWithSettings
                NotificationServiceWithSettings.send_observation_department_assigned(
                    department, observation, context_note_en=note, context_note_ar="",
                )
            except Exception as e:
                logger.warning(f"Failed to send department notification: {e}")

        return JsonResponse({
            "success": True,
            "message": message,
        })

    except Exception as e:
        logger.error(f"Error in observation_send_to: {str(e)}")
        return JsonResponse({
            "success": False,
            "error": str(_("An error occurred while sending the observation.")),
        }, status=500)


@login_required
@require_http_methods(["GET", "POST"])
def observation_department_response(request, pk):
    """
    Submit a department response for an observation.
    """
    observation = get_object_or_404(Observation, pk=pk)

    user = request.user
    if not (
        user.is_px_admin()
        or user.is_hospital_admin()
        or (user.is_champion() and observation.assigned_department == user.department)
    ):
        messages.error(request, "You don't have permission to respond to this observation.")
        return redirect("observations:observation_detail", pk=pk)

    if request.method == "POST":
        response_en = request.POST.get("response_en", "").strip()
        response_ar = request.POST.get("response_ar", "").strip()
        response = response_en or response_ar

        if not response:
            messages.error(request, "Please enter a response in at least one language.")
            return redirect("observations:observation_department_response", pk=pk)

        observation.department_response_en = response_en
        observation.department_response_ar = response_ar
        observation.department_responded_at = timezone.now()
        observation.department_responded_by = request.user
        observation.dept_response_is_overdue = False
        observation.dept_response_acceptance_status = "pending"
        observation.dept_response_accepted_by = None
        observation.dept_response_accepted_at = None
        observation.dept_response_acceptance_notes = ""
        observation.save()

        # Generate AI summary
        try:
            from apps.core.ai_service import AIService
            import json

            prompt = f"""You are an AI assistant for a hospital patient experience system. Summarize the following department response to a staff observation in 2-3 concise sentences.

Observation: {observation.description[:500]}
Department response: {response[:500]}

Generate a JSON response with:
- "summary_en": A brief summary of the department's response in English (2-3 sentences)
- "summary_ar": The same summary translated to Modern Standard Arabic"""

            result = AIService.chat_completion(
                prompt=prompt,
                response_format="json_object",
            )
            parsed = json.loads(result)
            observation.department_response_summary_en = parsed.get("summary_en", "")
            observation.department_response_summary_ar = parsed.get("summary_ar", "")
            observation.save(update_fields=["department_response_summary_en", "department_response_summary_ar"])
        except Exception as e:
            logger.warning(f"AI summary of department response failed: {e}")

        ObservationStatusLog.objects.create(
            observation=observation,
            from_status=observation.status,
            to_status=observation.status,
            changed_by=user,
            comment=f"Department response submitted by {user.get_full_name()}",
        )

        # Create note
        ObservationNote.objects.create(
            observation=observation,
            note=f"Department response submitted by {user.get_full_name()}",
            created_by=user,
            is_internal=True,
        )

        try:
            from apps.notifications.services import NotificationService, get_email_header_html
            from apps.core.utils import build_public_track_url

            track_url = build_public_track_url("observation", observation.tracking_code)

            if observation.reporter_phone:
                NotificationService.send_sms(
                    phone=observation.reporter_phone,
                    message=f"PX360: Your observation {observation.tracking_code} has been responded to. View details: {track_url}",
                    related_object=observation,
                    metadata={"notification_type": "observation_department_response"},
                )

            if observation.reporter_email:
                email_subject = f"PX360: Response to Your Observation {observation.tracking_code}"
                email_body = (
                    f"Dear Valued Reporter,\n\n"
                    f"Your observation {observation.tracking_code} has been responded to.\n\n"
                    f"To view the full response, please visit:\n{track_url}\n\n"
                    f"Thank you for your contribution.\n\n"
                    f"Tracking Code: {observation.tracking_code}\n"
                    f"This is an automated message from PX 360."
                )
                NotificationService.send_email(
                    email=observation.reporter_email,
                    subject=email_subject,
                    message=email_body,
                    html_message=f"""
<div style="font-family: 'Segoe UI', Tahoma, sans-serif; max-width: 600px; margin: 0 auto; border: 1px solid #e5e7eb; border-radius: 8px; overflow: hidden;">
    {get_email_header_html()}
    <div style="padding: 20px;">
        <h2 style="color: #005696; font-size: 18px; margin: 0 0 12px 0;">Response to Your Observation</h2>
        <p style="margin: 0 0 12px 0;">Dear Valued Reporter,</p>
        <p style="margin: 0 0 12px 0;">Your observation <strong>{observation.tracking_code}</strong> has been responded to.</p>
        <div style="text-align: center; margin: 20px 0;">
            <a href="{track_url}" style="background: #005696; color: white; padding: 10px 24px; border-radius: 8px; text-decoration: none; font-weight: 600;">View Response</a>
        </div>
        <p style="margin: 0 0 6px 0; color: #6b7280; font-size: 13px;">Tracking Code: {observation.tracking_code}</p>
        <p style="margin: 0 0 6px 0; color: #6b7280; font-size: 13px;">Thank you for your contribution.</p>
    </div>
</div>
""",
                    related_object=observation,
                    metadata={"notification_type": "observation_department_response_email"},
                )
        except Exception as e:
            logger.warning(f"Failed to send observation response notification: {e}")

        messages.success(request, "Department response submitted successfully.")
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            from django.http import JsonResponse
            from django.urls import reverse
            redirect_url = reverse("organizations:department_detail", kwargs={"pk": user.department.pk}) if user.department else reverse("observations:observation_detail", kwargs={"pk": pk})
            return JsonResponse({"success": True, "redirect_url": redirect_url})
        if user.department:
            return redirect("organizations:department_detail", pk=user.department.pk)
        return redirect("observations:observation_detail", pk=pk)

    context = {
        "observation": observation,
    }
    return render(request, "observations/observation_department_response.html", context)


@login_required
@require_http_methods(["POST"])
def observation_review_dept_response(request, pk):
    observation = get_object_or_404(Observation, pk=pk)

    user = request.user
    if not (user.is_px_admin() or user.is_hospital_admin()):
        messages.error(request, "You don't have permission to review department responses.")
        return redirect("observations:observation_detail", pk=pk)

    if not observation.department_responded_at:
        messages.error(request, "No department response to review.")
        return redirect("observations:observation_detail", pk=pk)

    status = request.POST.get("acceptance_status")
    if status not in ("acceptable", "not_acceptable"):
        messages.error(request, "Invalid acceptance status.")
        return redirect("observations:observation_detail", pk=pk)

    notes = request.POST.get("acceptance_notes", "").strip()

    if status == "not_acceptable":
        observation.dept_response_acceptance_status = "not_acceptable"
        observation.dept_response_accepted_by = user
        observation.dept_response_accepted_at = timezone.now()
        observation.dept_response_acceptance_notes = notes
        observation.department_response_en = ""
        observation.department_response_ar = ""
        observation.department_response_summary_en = ""
        observation.department_response_summary_ar = ""
        observation.department_responded_at = None
        observation.department_responded_by = None
        observation.save(
            update_fields=[
                "dept_response_acceptance_status",
                "dept_response_accepted_by",
                "dept_response_accepted_at",
                "dept_response_acceptance_notes",
                "department_response_en",
                "department_response_ar",
                "department_response_summary_en",
                "department_response_summary_ar",
                "department_responded_at",
                "department_responded_by",
            ]
        )

        dept = observation.assigned_department
        if dept and dept.champion and dept.champion.user and dept.champion.user.email:
            try:
                from apps.notifications.services import NotificationService, get_email_header_html

                NotificationService.send_email(
                    email=dept.champion.user.email,
                    subject=f"Action Required: Observation {observation.tracking_code} - Response Rejected",
                    message=(
                        f"Your department's response for observation {observation.tracking_code} has been rejected.\n\n"
                        f"Reason: {notes}\n\n"
                        f"Please revise and resubmit your response."
                    ),
                    html_message=f"""
<div style="font-family: 'Segoe UI', Tahoma, sans-serif; max-width: 600px; margin: 0 auto; border: 1px solid #e5e7eb; border-radius: 8px; overflow: hidden;">
    {get_email_header_html()}
    <div style="padding: 20px;">
        <h2 style="color: #005696; font-size: 18px; margin: 0 0 12px 0;">Response Rejected - Observation {observation.tracking_code}</h2>
        <p style="margin: 0 0 12px 0;">Your department's response for observation <strong>{observation.tracking_code}</strong> has been rejected.</p>
        <div style="background: #fef2f2; padding: 12px; border-radius: 6px; margin: 0 0 12px 0;">
            <p style="margin: 0;"><strong>Reason:</strong> {notes}</p>
        </div>
        <p style="margin: 0; color: #6b7280;">Please revise and resubmit your response.</p>
    </div>
</div>
""",
                    related_object=observation,
                )
            except Exception:
                import logging
                logging.getLogger(__name__).exception("Failed to send observation dept response rejection email")

        ObservationNote.objects.create(
            observation=observation,
            note=f"Department response rejected by {user.get_full_name()}. Reason: {notes}",
            created_by=user,
            is_internal=True,
        )

        messages.success(request, "Department response rejected. The department has been notified to resubmit.")
    else:
        observation.dept_response_acceptance_status = status
        observation.dept_response_accepted_by = user
        observation.dept_response_accepted_at = timezone.now()
        observation.dept_response_acceptance_notes = notes
        observation.save(
            update_fields=[
                "dept_response_acceptance_status",
                "dept_response_accepted_by",
                "dept_response_accepted_at",
                "dept_response_acceptance_notes",
            ]
        )

        ObservationStatusLog.objects.create(
            observation=observation,
            from_status=observation.status,
            to_status=observation.status,
            changed_by=user,
            comment=f"Department response marked as {status} by {user.get_full_name()}",
        )

        ObservationNote.objects.create(
            observation=observation,
            note=f"Department response review: {status}. {notes}",
            created_by=user,
            is_internal=True,
        )

        messages.success(request, f"Department response marked as {status}.")

    return redirect("observations:observation_detail", pk=pk)


@login_required
@require_http_methods(["POST"])
def observation_send_dept_response_reminder(request, pk):
    observation = get_object_or_404(Observation, pk=pk)

    user = request.user
    if not (user.is_px_admin() or user.is_hospital_admin()):
        messages.error(request, "You don't have permission to send reminders.")
        return redirect("observations:observation_detail", pk=pk)

    if observation.department_responded_at:
        messages.warning(request, "Department has already responded.")
        return redirect("observations:observation_detail", pk=pk)

    dept = observation.assigned_department
    if not dept:
        messages.error(request, "No department assigned.")
        return redirect("observations:observation_detail", pk=pk)

    reminder_type = request.POST.get("reminder_type", "first")

    try:
        from apps.notifications.services import NotificationService, get_email_header_html

        recipients = []
        if dept.champion and dept.champion.user and dept.champion.user.email:
            recipients.append(dept.champion.user)

        for recipient in recipients:
            NotificationService.send_email(
                email=recipient.email,
                subject=f"Reminder: Observation {observation.tracking_code} - Response Required",
                message=f"This is a reminder that observation {observation.tracking_code} is awaiting your department's response. Please submit your response as soon as possible.",
                html_message=f"""
<div style="font-family: 'Segoe UI', Tahoma, sans-serif; max-width: 600px; margin: 0 auto; border: 1px solid #e5e7eb; border-radius: 8px; overflow: hidden;">
    {get_email_header_html()}
    <div style="padding: 20px;">
        <h2 style="color: #005696; font-size: 18px; margin: 0 0 12px 0;">Reminder: Response Required</h2>
        <p style="margin: 0 0 12px 0;">This is a reminder that observation <strong>{observation.tracking_code}</strong> is awaiting your department's response.</p>
        <p style="margin: 0; color: #6b7280;">Please submit your response as soon as possible.</p>
    </div>
</div>
""",
                related_object=observation,
            )

        if reminder_type == "first":
            observation.dept_response_reminder_sent_at = timezone.now()
        else:
            observation.dept_response_second_reminder_sent_at = timezone.now()
        observation.save()

        ObservationNote.objects.create(
            observation=observation,
            note=f"Manual {reminder_type} reminder sent by {user.get_full_name()}",
            created_by=user,
            is_internal=True,
        )

        messages.success(request, f"Reminder sent to {len(recipients)} recipient(s).")
    except Exception as e:
        logger.error(f"Failed to send reminder: {e}")
        messages.error(request, "Failed to send reminder.")

    return redirect("observations:observation_detail", pk=pk)


# =============================================================================
# CATEGORY MANAGEMENT VIEWS
# =============================================================================


@login_required
@permission_required("observations.manage_categories", raise_exception=True)
def category_list(request):
    """
    List observation categories.
    """
    categories = ObservationCategory.objects.all().order_by("sort_order", "name_en")

    context = {
        "categories": categories,
    }

    return render(request, "observations/category_list.html", context)


@login_required
@permission_required("observations.manage_categories", raise_exception=True)
@require_http_methods(["GET", "POST"])
def category_create(request):
    """
    Create new observation category.
    """
    if request.method == "POST":
        form = ObservationCategoryForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, "Category created successfully.")
            return redirect("observations:category_list")
    else:
        form = ObservationCategoryForm()

    context = {
        "form": form,
        "title": "Create Category",
    }

    return render(request, "observations/category_form.html", context)


@login_required
@permission_required("observations.manage_categories", raise_exception=True)
@require_http_methods(["GET", "POST"])
def category_edit(request, pk):
    """
    Edit observation category.
    """
    category = get_object_or_404(ObservationCategory, pk=pk)

    if request.method == "POST":
        form = ObservationCategoryForm(request.POST, instance=category)
        if form.is_valid():
            form.save()
            messages.success(request, "Category updated successfully.")
            return redirect("observations:category_list")
    else:
        form = ObservationCategoryForm(instance=category)

    context = {
        "form": form,
        "category": category,
        "title": "Edit Category",
    }

    return render(request, "observations/category_form.html", context)


@login_required
@permission_required("observations.manage_categories", raise_exception=True)
@require_http_methods(["POST"])
def category_delete(request, pk):
    """
    Delete observation category.
    """
    category = get_object_or_404(ObservationCategory, pk=pk)

    # Check if category is in use
    if category.observations.exists():
        messages.error(request, "Cannot delete category that is in use.")
        return redirect("observations:category_list")

    category.delete()
    messages.success(request, "Category deleted successfully.")
    return redirect("observations:category_list")


# =============================================================================
# AJAX/API HELPERS
# =============================================================================


@login_required
def get_users_by_department(request):
    """
    Get users for a department (AJAX).
    """
    department_id = request.GET.get("department_id")
    if not department_id:
        return JsonResponse({"users": []})

    users = User.objects.filter(is_active=True, department_id=department_id).values(
        "id", "first_name", "last_name", "email"
    )

    return JsonResponse(
        {
            "users": [
                {
                    "id": str(u["id"]),
                    "name": f"{u['first_name']} {u['last_name']}",
                    "email": u["email"],
                }
                for u in users
            ]
        }
    )


# =============================================================================
# UTILITY FUNCTIONS
# =============================================================================


def get_client_ip(request):
    """
    Get client IP address from request.
    """
    x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
    if x_forwarded_for:
        ip = x_forwarded_for.split(",")[0].strip()
    else:
        ip = request.META.get("REMOTE_ADDR")
    return ip


@login_required
@require_http_methods(["POST"])
def observation_soft_delete(request, pk):
    observation = get_object_or_404(Observation, pk=pk)
    if not (request.user.is_px_admin() or request.user.is_hospital_admin()):
        return HttpResponseForbidden(_("You don't have permission to delete observations."))
    observation.soft_delete(user=request.user)
    messages.success(request, _("Observation moved to trash."))
    return redirect("observations:observation_list")


@login_required
@require_http_methods(["POST"])
def observation_restore(request, pk):
    observation = get_object_or_404(Observation.all_objects, pk=pk, is_deleted=True)
    if not (request.user.is_px_admin() or request.user.is_hospital_admin()):
        return HttpResponseForbidden(_("You don't have permission to restore observations."))
    observation.restore()
    messages.success(request, _("Observation restored successfully."))
    return redirect("observations:observation_list")


def observation_respond_with_token(request, pk, token):
    """
    Public-facing form for department staff to submit response to an observation.
    Does NOT require authentication. Validates token and checks validity.
    """
    from apps.core.ai_service import AIService
    from apps.notifications.services import NotificationService
    from apps.core.utils import build_public_track_url

    observation = get_object_or_404(Observation, pk=pk)

    if observation.response_token != token or not observation.response_token:
        return render(request, "observations/response_token_invalid.html", {"observation": observation})

    if observation.response_token_used:
        return render(request, "observations/response_already_submitted.html", {"observation": observation})

    if request.method == "POST":
        response_en = request.POST.get("response_en", "").strip()
        response_ar = request.POST.get("response_ar", "").strip()
        response = response_en or response_ar

        if not response:
            return render(request, "observations/response_form_token.html", {
                "observation": observation,
                "error": "Please enter a response in at least one language.",
            })

        observation.department_response_en = response_en
        observation.department_response_ar = response_ar
        observation.department_responded_at = timezone.now()
        observation.dept_response_is_overdue = False
        observation.dept_response_acceptance_status = "pending"
        observation.response_token_used = True
        observation.save()

        # AI summary
        try:
            import json
            prompt = f"""Summarize the following department response to a staff observation in 2-3 concise sentences.

Observation: {observation.description[:500]}
Department response: {response[:500]}

Generate JSON with "summary_en" and "summary_ar"."""
            result = AIService.chat_completion(prompt=prompt, response_format="json_object")
            parsed = json.loads(result)
            observation.department_response_summary_en = parsed.get("summary_en", "")
            observation.department_response_summary_ar = parsed.get("summary_ar", "")
            observation.save(update_fields=["department_response_summary_en", "department_response_summary_ar"])
        except Exception:
            pass

        # Notify reporter
        track_url = build_public_track_url("observation", observation.tracking_code)
        if observation.reporter_phone:
            try:
                NotificationService.send_sms(
                    phone=observation.reporter_phone,
                    message=f"PX360: Your observation {observation.tracking_code} has been responded to. View: {track_url}",
                    related_object=observation,
                )
            except Exception:
                pass
        if observation.reporter_email:
            try:
                NotificationService.send_email(
                    email=observation.reporter_email,
                    subject=f"PX360: Response to Your Observation {observation.tracking_code}",
                    message=f"Your observation has been responded to.\n\nView: {track_url}",
                    related_object=observation,
                )
            except Exception:
                pass

        return render(request, "observations/response_success_token.html", {"observation": observation})

    return render(request, "observations/response_form_token.html", {"observation": observation})
