"""
Organizations views and viewsets
"""

from django.db import models
from django.http import JsonResponse
from rest_framework import status, viewsets
from rest_framework.decorators import action, api_view, permission_classes
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.response import Response

from apps.accounts.permissions import (
    CanAccessDepartmentData,
    CanAccessHospitalData,
    IsPXAdminOrHospitalAdmin,
    IsPXAdmin,
)

from .models import (
    Area,
    Department,
    Hospital,
    Organization,
    Patient,
    Staff,
    LegacyLocation,
    LegacyMainSection,
    LegacySubSection,
    OrgSubSection,
    Section,
)
from .models import Staff as StaffModel
from .serializers import (
    DepartmentSerializer,
    HospitalSerializer,
    LocationSerializer,
    MainSectionSerializer,
    OrganizationSerializer,
    OrgSubSectionSerializer,
    PatientListSerializer,
    PatientSerializer,
    StaffSerializer,
    SubSectionSerializer,
)


class OrganizationViewSet(viewsets.ModelViewSet):
    """
    ViewSet for Organization model.

    Permissions:
    - PX Admins can manage organizations
    - Others can view organizations
    """

    queryset = Organization.objects.all()
    serializer_class = OrganizationSerializer
    permission_classes = [IsAuthenticated]
    filterset_fields = ["status", "city"]
    search_fields = ["name", "name_ar", "code", "license_number"]
    ordering_fields = ["name", "created_at"]
    ordering = ["name"]

    def get_queryset(self):
        """Filter organizations based on user role"""
        queryset = super().get_queryset().prefetch_related("hospitals")
        user = self.request.user

        # PX Admins see all organizations
        if user.is_px_admin():
            return queryset

        # Hospital Admins and others see their organization
        if user.is_hospital_admin() and user.hospital and user.hospital.organization:
            return queryset.filter(id=user.hospital.organization.id)

        # Others with hospital see their organization
        if user.hospital and user.hospital.organization:
            return queryset.filter(id=user.hospital.organization.id)

        return queryset.none()


class HospitalViewSet(viewsets.ModelViewSet):
    """
    ViewSet for Hospital model.

    Permissions:
    - PX Admins and Hospital Admins can manage hospitals
    - Others can view hospitals they belong to
    """

    queryset = Hospital.objects.all()
    serializer_class = HospitalSerializer
    permission_classes = [IsAuthenticated, CanAccessHospitalData]
    filterset_fields = ["status", "city", "organization"]
    search_fields = ["name", "name_ar", "code", "city"]
    ordering_fields = ["name", "created_at"]
    ordering = ["name"]

    def get_queryset(self):
        """Filter hospitals based on user role"""
        queryset = super().get_queryset()
        user = self.request.user

        # PX Admins see all hospitals
        if user.is_px_admin():
            return queryset

        # Hospital Admins see their hospital
        if user.is_hospital_admin() and user.hospital:
            return queryset.filter(id=user.hospital.id)

        # Department Managers see their hospital
        if user.is_department_manager() and user.hospital:
            return queryset.filter(id=user.hospital.id)

        # Others see hospitals they're associated with
        if user.hospital:
            return queryset.filter(id=user.hospital.id)

        return queryset.none()


class DepartmentViewSet(viewsets.ModelViewSet):
    """
    ViewSet for Department model.

    Permissions:
    - PX Admins and Hospital Admins can manage departments
    - Department Managers can view their department
    """

    queryset = Department.objects.all()
    serializer_class = DepartmentSerializer
    permission_classes = [IsAuthenticated, CanAccessDepartmentData]
    filterset_fields = ["status", "hospital", "parent", "hospital__organization", "category"]
    search_fields = ["name", "name_ar", "code"]
    ordering_fields = ["name", "created_at"]
    ordering = ["hospital", "name"]

    def get_queryset(self):
        """Filter departments based on user role"""
        queryset = super().get_queryset().select_related("hospital", "parent", "manager")
        user = self.request.user

        # PX Admins see all departments
        if user.is_px_admin():
            return queryset

        # Hospital Admins see departments in their hospital
        if user.is_hospital_admin() and user.hospital:
            return queryset.filter(hospital=user.hospital)

        # Department Managers see their department and sub-departments
        if user.is_department_manager() and user.department:
            return queryset.filter(hospital=user.hospital).filter(
                models.Q(id=user.department.id) | models.Q(parent=user.department)
            )

        # Others see departments in their hospital
        if user.hospital:
            return queryset.filter(hospital=user.hospital)

        return queryset.none()


class StaffViewSet(viewsets.ModelViewSet):
    """
    ViewSet for Staff model.

    Permissions:
    - PX Admins and Hospital Admins can manage staff
    - Others can view staff
    """

    queryset = StaffModel.objects.all()
    serializer_class = StaffSerializer
    permission_classes = [IsAuthenticated]
    filterset_fields = [
        "status",
        "hospital",
        "department",
        "staff_type",
        "specialization",
        "job_title",
        "hospital__organization",
    ]
    search_fields = [
        "first_name",
        "last_name",
        "first_name_ar",
        "last_name_ar",
        "employee_id",
        "license_number",
        "job_title",
    ]
    ordering_fields = ["last_name", "created_at"]
    ordering = ["last_name", "first_name"]

    def get_permissions(self):
        """Set permissions based on action"""
        if self.action in [
            "create_user_account",
            "link_user",
            "unlink_user",
            "send_invitation",
            "reset_password_and_resend",
        ]:
            return [IsAuthenticated()]
        return super().get_permissions()

    def get_queryset(self):
        """Filter staff based on user role"""
        queryset = super().get_queryset().select_related("hospital", "department", "user")
        user = self.request.user

        # Source Users don't have access to staff management
        if user.is_source_user():
            return queryset.none()

        # PX Admins see staff in their selected hospital
        if user.is_px_admin():
            tenant_hospital = getattr(self.request, "tenant_hospital", None)
            if tenant_hospital:
                return queryset.filter(hospital=tenant_hospital)
            return queryset

        # Hospital Admins see staff in their hospital
        if user.is_hospital_admin() and user.hospital:
            return queryset.filter(hospital=user.hospital)

        # Department Managers see staff in their department
        if user.is_department_manager() and user.department:
            return queryset.filter(department=user.department)

        # Others see staff in their hospital
        if user.hospital:
            return queryset.filter(hospital=user.hospital)

        return queryset.none()

    @action(detail=False, methods=["get"], url_path="search")
    def search(self, request):
        q = request.query_params.get("q", "").strip()
        queryset = self.get_queryset().filter(status="active")
        if q:
            queryset = queryset.filter(
                models.Q(first_name__icontains=q)
                | models.Q(last_name__icontains=q)
                | models.Q(name__icontains=q)
                | models.Q(name_ar__icontains=q)
                | models.Q(employee_id__icontains=q)
            )
        queryset = queryset[:20]
        data = [
            {"id": s.id, "first_name": s.first_name, "last_name": s.last_name, "employee_id": s.employee_id}
            for s in queryset
        ]
        return Response(data)

    @action(detail=True, methods=["post"])
    def create_user_account(self, request, pk=None):
        """
        Create a user account for a staff member.
        Auto-generates username, password, and sends email.
        """
        staff = self.get_object()

        if staff.user:
            return Response({"error": "Staff member already has a user account"}, status=status.HTTP_400_BAD_REQUEST)

        # Check permissions
        user = request.user
        if not (user.is_px_admin() or user.is_hospital_admin() or user.is_department_manager()):
            return Response(
                {"error": "You do not have permission to create user accounts"}, status=status.HTTP_403_FORBIDDEN
            )

        # Hospital Admins can only create accounts for staff in their hospital
        if user.is_hospital_admin() and staff.hospital != user.hospital:
            return Response(
                {"error": "You can only create accounts for staff in your hospital"}, status=status.HTTP_403_FORBIDDEN
            )

        # Department Managers can only create accounts for staff in their department
        if user.is_department_manager() and (
            not user.department or staff.department != user.department
        ):
            return Response(
                {"error": "You can only create accounts for staff in your department"}, status=status.HTTP_403_FORBIDDEN
            )

        # Get role from request or default to 'staff'
        role = request.data.get('role', 'staff') if hasattr(request, 'data') else 'staff'
        allowed_roles = ['staff', 'px_employee', 'hospital_admin', 'department_manager']
        if role not in allowed_roles:
            role = 'staff'

        from .services import StaffService

        try:
            user_account, was_created, password = StaffService.create_user_for_staff(staff, role=role, request=request)

            if was_created:
                # Send password reset link
                try:
                    StaffService.send_password_reset_email(staff, request)
                    message = "User account created and password reset link emailed successfully"
                except Exception as e:
                    message = f"User account created. Email sending failed: {str(e)}"
            else:
                # Existing user was linked - no password to generate or email to send
                message = "Existing user account linked successfully. The staff member can now log in with their existing credentials."

            serializer = self.get_serializer(staff)
            return Response(
                {"message": message, "staff": serializer.data, "email": user_account.email, "was_created": was_created},
                status=status.HTTP_200_OK if not was_created else status.HTTP_201_CREATED,
            )

        except ValueError as e:
            return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=True, methods=["post"])
    def link_user(self, request, pk=None):
        """
        Link an existing user account to a staff member.
        """
        staff = self.get_object()

        if staff.user:
            return Response({"error": "Staff member already has a user account"}, status=status.HTTP_400_BAD_REQUEST)

        # Check permissions
        user = request.user
        if not user.is_px_admin() and not user.is_hospital_admin():
            return Response(
                {"error": "You do not have permission to link user accounts"}, status=status.HTTP_403_FORBIDDEN
            )

        # Hospital Admins can only link accounts for staff in their hospital
        if user.is_hospital_admin() and staff.hospital != user.hospital:
            return Response(
                {"error": "You can only link accounts for staff in your hospital"}, status=status.HTTP_403_FORBIDDEN
            )

        user_id = request.data.get("user_id")
        if not user_id:
            return Response({"error": "user_id is required"}, status=status.HTTP_400_BAD_REQUEST)

        from .services import StaffService

        try:
            StaffService.link_user_to_staff(staff, user_id, request=request)
            serializer = self.get_serializer(staff)
            return Response({"message": "User account linked successfully", "staff": serializer.data})

        except ValueError as e:
            return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=True, methods=["post"])
    def unlink_user(self, request, pk=None):
        """
        Remove user account association from a staff member.
        """
        staff = self.get_object()

        if not staff.user:
            return Response({"error": "Staff member has no user account"}, status=status.HTTP_400_BAD_REQUEST)

        # Check permissions
        user = request.user
        if not user.is_px_admin() and not user.is_hospital_admin():
            return Response(
                {"error": "You do not have permission to unlink user accounts"}, status=status.HTTP_403_FORBIDDEN
            )

        # Hospital Admins can only unlink accounts for staff in their hospital
        if user.is_hospital_admin() and staff.hospital != user.hospital:
            return Response(
                {"error": "You can only unlink accounts for staff in your hospital"}, status=status.HTTP_403_FORBIDDEN
            )

        from .services import StaffService

        try:
            StaffService.unlink_user_from_staff(staff, request=request)
            serializer = self.get_serializer(staff)
            return Response({"message": "User account unlinked successfully", "staff": serializer.data})

        except ValueError as e:
            return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=True, methods=["post"])
    def send_invitation(self, request, pk=None):
        """
        Send a password reset email to staff member.
        """
        staff = self.get_object()

        if not staff.user:
            return Response({"error": "Staff member has no user account"}, status=status.HTTP_400_BAD_REQUEST)

        # Check permissions
        user = request.user
        if not user.is_px_admin() and not user.is_hospital_admin():
            return Response(
                {"error": "You do not have permission to send invitations"}, status=status.HTTP_403_FORBIDDEN
            )

        # Hospital Admins can only send invitations to staff in their hospital
        if user.is_hospital_admin() and staff.hospital != user.hospital:
            return Response(
                {"error": "You can only send invitations to staff in your hospital"}, status=status.HTTP_403_FORBIDDEN
            )

        from .services import StaffService

        try:
            StaffService.send_password_reset_email(staff, request)

            serializer = self.get_serializer(staff)
            return Response({"message": "Password reset email sent successfully", "staff": serializer.data})

        except ValueError as e:
            return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=True, methods=["post"])
    def reset_password_and_resend(self, request, pk=None):
        """
        Reset user password and resend password reset link.

        This action sends a secure one-time password reset link to the staff member.
        """
        staff = self.get_object()

        if not staff.user:
            return Response({"error": "Staff member has no user account"}, status=status.HTTP_400_BAD_REQUEST)

        # Check permissions
        user = request.user
        if not user.is_px_admin() and not user.is_hospital_admin():
            return Response(
                {"error": "You do not have permission to reset passwords"}, status=status.HTTP_403_FORBIDDEN
            )

        # Hospital Admins can only reset passwords for staff in their hospital
        if user.is_hospital_admin() and staff.hospital != user.hospital:
            return Response(
                {"error": "You can only reset passwords for staff in your hospital"}, status=status.HTTP_403_FORBIDDEN
            )

        from .services import StaffService

        try:
            # Reset password and resend credentials
            _, notification_log = StaffService.reset_password_and_resend_credentials(staff, request=request)

            serializer = self.get_serializer(staff)
            return Response(
                {
                    "success": True,
                    "message": "Password reset link sent successfully",
                    "email_sent_to": staff.email,
                    "notification_log_id": str(notification_log.id) if notification_log else None,
                    "staff": serializer.data,
                }
            )

        except ValueError as e:
            return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=False, methods=["get"])
    def hierarchy(self, request):
        """
        Get staff hierarchy as D3-compatible JSON.
        Used for interactive tree visualization.

        Note: This action uses a more permissive queryset to allow all authenticated
        users to view the organization hierarchy for visualization purposes.
        """
        from django.db.models import Q

        # Get filter parameters
        hospital_id = request.query_params.get("hospital")
        department_id = request.query_params.get("department")
        search = request.query_params.get("search", "").strip()

        # Build base queryset - use all staff for hierarchy visualization
        # This allows any authenticated user to see the full organizational structure
        queryset = StaffModel.objects.all().select_related("report_to", "hospital", "department")

        # Apply filters
        if hospital_id:
            queryset = queryset.filter(hospital_id=hospital_id)
        if department_id:
            queryset = queryset.filter(department_id=department_id)
        if search:
            queryset = queryset.filter(
                Q(first_name__icontains=search) | Q(last_name__icontains=search) | Q(employee_id__icontains=search)
            )

        # Get all staff with their managers
        staff_list = queryset.select_related("report_to", "hospital", "department")

        # Build staff lookup dictionary
        staff_dict = {staff.id: staff for staff in staff_list}

        # Build hierarchy tree
        def build_node(staff):
            """Recursively build hierarchy node for D3"""
            node = {
                "id": staff.id,
                "name": staff.get_full_name(),
                "employee_id": staff.employee_id,
                "job_title": staff.job_title or "",
                "hospital": staff.hospital.name if staff.hospital else "",
                "department": staff.department.name if staff.department else "",
                "status": staff.status,
                "staff_type": staff.staff_type,
                "team_size": 0,  # Will be calculated
                "children": [],
            }

            # Find direct reports
            direct_reports = [s for s in staff_list if s.report_to_id == staff.id]

            # Recursively build children
            for report in direct_reports:
                child_node = build_node(report)
                node["children"].append(child_node)
                node["team_size"] += 1 + child_node["team_size"]

            return node

        # Group root nodes by organization
        from collections import defaultdict

        org_groups = defaultdict(list)

        # Find root nodes (staff with no manager in the filtered set)
        root_staff = [
            staff for staff in staff_list if staff.report_to_id is None or staff.report_to_id not in staff_dict
        ]

        # Group root staff by organization
        for staff in root_staff:
            if staff.hospital and staff.hospital.organization:
                org_name = staff.hospital.organization.name
            else:
                org_name = "Organization"
            org_groups[org_name].append(staff)

        # Build hierarchy for each organization
        hierarchy = []
        top_managers = 0

        for org_name, org_root_staff in org_groups.items():
            # Build hierarchy nodes for this organization's root staff
            org_root_nodes = [build_node(staff) for staff in org_root_staff]

            # Calculate total team size for this organization
            org_team_size = sum(node["team_size"] + 1 for node in org_root_nodes)

            # Create organization node as parent
            org_node = {
                "id": None,
                "name": org_name,
                "employee_id": "",
                "job_title": "Organization",
                "hospital": "",
                "department": "",
                "status": "active",
                "staff_type": "organization",
                "team_size": org_team_size,
                "children": org_root_nodes,
                "is_organization_root": True,
            }

            hierarchy.append(org_node)
            top_managers += len(org_root_nodes)

        # If there are multiple organizations, wrap them in a single root
        if len(hierarchy) > 1:
            total_team_size = sum(node["team_size"] for node in hierarchy)
            hierarchy = [
                {
                    "id": None,
                    "name": "All Organizations",
                    "employee_id": "",
                    "job_title": "",
                    "hospital": "",
                    "department": "",
                    "status": "active",
                    "staff_type": "root",
                    "team_size": total_team_size,
                    "children": hierarchy,
                    "is_virtual_root": True,
                }
            ]

        # Calculate statistics
        total_staff = len(staff_list)

        return Response(
            {"hierarchy": hierarchy, "statistics": {"total_staff": total_staff, "top_managers": top_managers}}
        )


class PatientViewSet(viewsets.ModelViewSet):
    """
    ViewSet for Patient model.

    Permissions:
    - All authenticated users can view patients
    - PX Admins and Hospital Admins can manage patients
    """

    queryset = Patient.objects.all()
    permission_classes = [IsAuthenticated]
    filterset_fields = ["status", "gender", "primary_hospital", "city", "primary_hospital__organization"]
    search_fields = ["mrn", "national_id_hash", "first_name", "last_name", "phone", "email"]
    ordering_fields = ["last_name", "created_at"]
    ordering = ["last_name", "first_name"]

    def get_serializer_class(self):
        """Use simplified serializer for list view"""
        if self.action == "list":
            return PatientListSerializer
        return PatientSerializer

    def get_queryset(self):
        """Filter patients based on user role"""
        queryset = super().get_queryset().select_related("primary_hospital")
        user = self.request.user

        # PX Admins see patients in their selected hospital
        if user.is_px_admin():
            tenant_hospital = getattr(self.request, "tenant_hospital", None)
            if tenant_hospital:
                return queryset.filter(primary_hospital=tenant_hospital)
            return queryset

        # Hospital Admins see patients in their hospital
        if user.is_hospital_admin() and user.hospital:
            return queryset.filter(primary_hospital=user.hospital)

        # Others see patients in their hospital
        if user.hospital:
            return queryset.filter(primary_hospital=user.hospital)

        return queryset

    @action(detail=False, methods=["get"], url_path="search")
    def search(self, request):
        q = request.query_params.get("q", "").strip()
        queryset = self.get_queryset().filter(status="active")
        if q:
            from apps.core.encryption import compute_national_id_hash

            nid_hash = compute_national_id_hash(q)
            queryset = queryset.filter(
                models.Q(mrn__icontains=q)
                | models.Q(first_name__icontains=q)
                | models.Q(last_name__icontains=q)
                | models.Q(national_id_hash=nid_hash)
                | models.Q(phone__icontains=q)
            )
        queryset = queryset[:20]
        data = [
            {
                "id": p.id,
                "first_name": p.first_name,
                "last_name": p.last_name,
                "mrn": p.mrn,
                "national_id_masked": p.get_masked_national_id(),
            }
            for p in queryset
        ]
        return Response(data)


class LegacyLocationViewSet(viewsets.ReadOnlyModelViewSet):
    """
    ViewSet for LegacyLocation model.

    Publicly accessible for complaint form dropdowns.
    """

    queryset = LegacyLocation.objects.all()
    serializer_class = LocationSerializer
    permission_classes = []  # Public access
    ordering = ["id"]


class LegacyMainSectionViewSet(viewsets.ReadOnlyModelViewSet):
    """
    ViewSet for LegacyMainSection model.

    Publicly accessible for complaint form dropdowns.
    """

    queryset = LegacyMainSection.objects.all()
    serializer_class = MainSectionSerializer
    permission_classes = []  # Public access
    ordering = ["id"]


class LegacySubSectionViewSet(viewsets.ReadOnlyModelViewSet):
    """
    ViewSet for LegacySubSection model.

    Publicly accessible for complaint form dropdowns.
    Supports filtering by location and main_section.
    """

    queryset = LegacySubSection.objects.all()
    serializer_class = SubSectionSerializer
    permission_classes = []  # Public access
    filterset_fields = ["location", "main_section"]
    ordering = ["internal_id"]


class OrgSubSectionViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Section.objects.filter(status="active").select_related("department")
    serializer_class = OrgSubSectionSerializer
    filterset_fields = ["department"]
    search_fields = ["name_en", "name_ar", "code"]


# Backward compatibility alias
SectionViewSet = OrgSubSectionViewSet


# Dedicated API endpoints for complaint form dropdowns
# These avoid conflicts with UI routes
@api_view(["GET"])
@permission_classes([])
def api_location_list(request):
    """API endpoint for location dropdown (public access)"""
    locations = LegacyLocation.active_locations()
    serializer = LocationSerializer(locations, many=True)
    return Response(serializer.data)


@api_view(["GET"])
@permission_classes([])
def api_main_section_list(request):
    """API endpoint for main section dropdown (public access)"""
    sections = LegacyMainSection.objects.all().order_by("id")
    serializer = MainSectionSerializer(sections, many=True)
    return Response(serializer.data)


@api_view(["GET"])
@permission_classes([])
def api_subsection_list(request):
    """API endpoint for subsection dropdown (public access)
    Optional query params:
    - location: Filter by location ID
    - main_section: Filter by main section ID
    """
    subsections = LegacySubSection.objects.all().order_by("name")

    location_id = request.GET.get("location")
    main_section_id = request.GET.get("main_section")

    if location_id:
        subsections = subsections.filter(location_id=location_id)
    if main_section_id:
        subsections = subsections.filter(main_section_id=main_section_id)

    serializer = SubSectionSerializer(subsections, many=True)
    return Response(serializer.data)


# AJAX endpoints for complaint form cascading dropdowns
@api_view(["GET"])
@permission_classes([])
def ajax_main_sections(request):
    """
    AJAX endpoint for main sections filtered by location.
    Used in complaint form for cascading dropdown.
    """
    location_id = request.GET.get("location_id")

    if location_id:
        # Get main sections that have subsections for this location
        available_section_ids = (
            LegacySubSection.objects.filter(location_id=location_id).values_list("main_section_id", flat=True).distinct()
        )

        main_sections = LegacyMainSection.objects.filter(id__in=available_section_ids).order_by("name_en")
    else:
        main_sections = LegacyMainSection.objects.none()

    serializer = MainSectionSerializer(main_sections, many=True)
    return Response({"sections": serializer.data})


@api_view(["GET"])
@permission_classes([])
def ajax_subsections(request):
    """
    AJAX endpoint for subsections filtered by location and main section.
    Used in complaint form for cascading dropdown.
    """
    location_id = request.GET.get("location_id")
    main_section_id = request.GET.get("main_section_id")

    if location_id and main_section_id:
        subsections = LegacySubSection.objects.filter(location_id=location_id, main_section_id=main_section_id).order_by(
            "name_en"
        )
    else:
        subsections = LegacySubSection.objects.none()

    serializer = SubSectionSerializer(subsections, many=True)
    return Response({"subsections": serializer.data})


def api_departments_by_category(request):
    from apps.organizations.serializers import DepartmentSerializer
    category = request.GET.get("category", "")
    hospital_id = request.GET.get("hospital", "")
    qs = Department.objects.filter(status="active")
    if category:
        qs = qs.filter(category=category)
    if hospital_id:
        qs = qs.filter(hospital_id=hospital_id)
    data = DepartmentSerializer(qs.order_by("name_en"), many=True).data
    return JsonResponse(data, safe=False)


def api_sections_by_department(request, department_id):
    from apps.organizations.serializers import OrgSubSectionSerializer
    qs = Section.objects.filter(department_id=department_id, status="active")
    data = OrgSubSectionSerializer(qs.order_by("name_en"), many=True).data
    return JsonResponse(data, safe=False)


def api_subsections_by_section(request, section_id):
    from apps.organizations.serializers import SubSectionSerializer
    qs = SubSection.objects.filter(section_id=section_id, status="active")
    data = SubSectionSerializer(qs.order_by("name_en"), many=True).data
    return JsonResponse(data, safe=False)


def api_areas_by_hospital(request):
    from apps.organizations.serializers import AreaSerializer

    qs = Area.objects.filter(status="active")
    hospital_id = request.GET.get("hospital")
    if hospital_id:
        qs = qs.filter(hospital_id=hospital_id)
    location_type = request.GET.get("location_type")
    if location_type:
        qs = qs.filter(location_type=location_type)
    data = AreaSerializer(qs.order_by("name_en"), many=True).data
    return JsonResponse(data, safe=False)


def api_staff_by_department(request, department_id):
    qs = Staff.objects.filter(department_id=department_id, status="active")
    data = [
        {
            "id": str(s.id),
            "name": s.get_full_name(),
            "employee_id": s.employee_id or "",
            "title": s.job_title or "",
        }
        for s in qs.order_by("first_name", "last_name")
    ]
    return JsonResponse(data, safe=False)



@api_view(["GET"])
@permission_classes([])
def api_department_contacts(request, department_id):
    dept = Department.objects.filter(pk=department_id, status="active").first()
    if not dept:
        return JsonResponse({"error": "Department not found"}, status=404)
    holders = dept.get_role_holders()
    # Convert non-serializable Staff objects to dicts for JSON response
    serializable_holders = []
    for holder in holders:
        staff = holder.get("staff")
        serializable_holders.append(
            {
                "staff": {
                    "id": str(staff.id) if staff else None,
                    "name": staff.get_full_name() if staff else None,
                    "email": staff.email if staff else None,
                    "employee_id": staff.employee_id if staff else None,
                },
                "staff_id": holder.get("staff_id"),
                "name": holder.get("name"),
                "email": holder.get("email"),
                "role_field": holder.get("role_field"),
                "role_label": holder.get("role_label"),
            }
        )
    return JsonResponse(serializable_holders, safe=False)


@api_view(["GET"])
@permission_classes([])
def ajax_departments(request):
    """
    AJAX endpoint for departments filtered by hospital.
    Used in complaint form for cascading dropdown.
    """
    hospital_id = request.GET.get("hospital_id")

    if hospital_id:
        departments = Department.objects.filter(hospital_id=hospital_id, status="active").order_by("name")
    else:
        departments = Department.objects.none()

    serializer = DepartmentSerializer(departments, many=True)
    return Response({"departments": serializer.data})


@api_view(["GET"])
@permission_classes([IsAuthenticated])
def api_staff_hierarchy(request):
    """
    API endpoint for staff hierarchy data (used by D3 visualization).

    GET /organizations/api/staff/hierarchy/

    Query params:
    - hospital: Filter by hospital ID
    - department: Filter by department ID
    - max_depth: Maximum hierarchy depth to return (default: 3, use 0 for all)
    - flat: Return flat list instead of tree (for large datasets)

    Returns:
    {
        "hierarchy": [...],
        "statistics": {
            "total_staff": 100,
            "top_managers": 5
        }
    }
    """
    import time

    start_time = time.time()

    user = request.user
    cache_key = f"staff_hierarchy:{user.id}:{user.hospital_id if user.hospital else 'all'}"

    # Check cache first (30 second cache for real-time feel)
    from django.core.cache import cache

    cached_result = cache.get(cache_key)
    if cached_result:
        return Response(cached_result)

    # Get base queryset with only needed fields
    queryset = Staff.objects.select_related("hospital", "department", "report_to").only(
        "id",
        "first_name",
        "last_name",
        "employee_id",
        "job_title",
        "hospital__name",
        "department__name",
        "report_to_id",
        "status",
    )

    # Apply RBAC
    if user.is_px_admin() and hasattr(request, "tenant_hospital") and request.tenant_hospital:
        queryset = queryset.filter(hospital=request.tenant_hospital)
    elif not user.is_px_admin() and user.hospital:
        queryset = queryset.filter(hospital=user.hospital)

    # Apply filters
    hospital_filter = request.GET.get("hospital")
    if hospital_filter:
        queryset = queryset.filter(hospital_id=hospital_filter)
        cache_key += f":h:{hospital_filter}"

    department_filter = request.GET.get("department")
    if department_filter:
        queryset = queryset.filter(department_id=department_filter)
        cache_key += f":d:{department_filter}"

    # Get options
    max_depth = int(request.GET.get("max_depth", 3))
    flat_mode = request.GET.get("flat", "false").lower() == "true"

    # Fetch all staff as values for faster processing
    all_staff = list(queryset)
    total_count = len(all_staff)

    # OPTIMIZATION 1: Pre-calculate team sizes using a dictionary
    report_count = {}
    for staff in all_staff:
        if staff.report_to_id:
            report_count[staff.report_to_id] = report_count.get(staff.report_to_id, 0) + 1

    # OPTIMIZATION 2: Build lookup dictionaries
    staff_by_id = {str(s.id): s for s in all_staff}
    children_by_parent = {}
    for staff in all_staff:
        parent_id = str(staff.report_to_id) if staff.report_to_id else None
        if parent_id not in children_by_parent:
            children_by_parent[parent_id] = []
        children_by_parent[parent_id].append(staff)

    # OPTIMIZATION 3: Recursive function with depth limit and memoization
    def build_hierarchy_optimized(parent_id=None, current_depth=0):
        """Build hierarchy tree using pre-calculated lookups"""
        if max_depth > 0 and current_depth >= max_depth:
            return []

        children = children_by_parent.get(parent_id, [])
        result = []

        for staff in children:
            node = {
                "name": staff.get_localized_name() or staff.employee_id,
                "id": str(staff.id),
                "employee_id": staff.employee_id,
                "job_title": staff.job_title or "",
                "department": staff.department.name if staff.department else "",
                "hospital": staff.hospital.name if staff.hospital else "",
                "team_size": report_count.get(str(staff.id), 0),
                "has_children": str(staff.id) in children_by_parent,
                "children": [],  # Lazy load - children fetched on expand
            }

            # Only build children if not at max depth
            if max_depth == 0 or current_depth < max_depth - 1:
                node["children"] = build_hierarchy_optimized(str(staff.id), current_depth + 1)

            result.append(node)

        return result

    # Build hierarchy starting from top-level
    hierarchy = build_hierarchy_optimized(None, 0)

    # Calculate statistics
    top_managers = len(children_by_parent.get(None, []))

    result = {
        "hierarchy": hierarchy,
        "statistics": {
            "total_staff": total_count,
            "top_managers": top_managers,
            "load_time_ms": int((time.time() - start_time) * 1000),
        },
    }

    # Cache for 30 seconds
    cache.set(cache_key, result, 30)

    return Response(result)


@api_view(["GET"])
@permission_classes([IsAuthenticated])
def api_staff_hierarchy_children(request, staff_id):
    """
    API endpoint to fetch children of a specific staff member.
    Used for lazy loading in D3 visualization.

    GET /organizations/api/staff/hierarchy/{staff_id}/children/

    Returns:
    {
        "staff_id": "uuid",
        "children": [...]
    }
    """
    user = request.user

    # Get the parent staff member
    try:
        parent = Staff.objects.select_related("hospital", "department").get(id=staff_id)
    except Staff.DoesNotExist:
        return Response({"error": "Staff not found"}, status=404)

    # Check permission
    if not user.is_px_admin() and user.hospital != parent.hospital:
        return Response({"error": "Permission denied"}, status=403)

    # Get children with optimized query
    children = (
        Staff.objects.select_related("hospital", "department")
        .filter(report_to=parent)
        .only("id", "first_name", "last_name", "employee_id", "job_title", "hospital__name", "department__name")
    )

    # Pre-calculate which children have their own children
    child_ids = list(children.values_list("id", flat=True))
    children_with_reports = set(
        Staff.objects.filter(report_to_id__in=child_ids).values_list("report_to_id", flat=True).distinct()
    )

    result = []
    for staff in children:
        result.append(
            {
                "name": staff.get_localized_name() or staff.employee_id,
                "id": str(staff.id),
                "employee_id": staff.employee_id,
                "job_title": staff.job_title or "",
                "department": staff.department.name if staff.department else "",
                "hospital": staff.hospital.name if staff.hospital else "",
                "team_size": 0,  # Will be calculated on next expand
                "has_children": staff.id in children_with_reports,
                "children": [],  # Empty - load on next expand
            }
        )

    return Response({"staff_id": str(staff_id), "children": result})


@api_view(["GET"])
@permission_classes([IsAuthenticated])
def api_patient_search(request):
    """
    Standalone patient search API endpoint.

    Used by survey manual send form to search for patients.
    URL: /api/patients/search/?q=<query>&active=true
    """
    q = request.query_params.get("q", "").strip()
    queryset = Patient.objects.filter(status="active")

    # Filter by user's hospital if not admin
    user = request.user
    if hasattr(user, "hospital") and user.hospital and not user.is_superuser:
        queryset = queryset.filter(primary_hospital=user.hospital)

    if q:
        queryset = queryset.filter(
            models.Q(mrn__icontains=q)
            | models.Q(first_name__icontains=q)
            | models.Q(last_name__icontains=q)
            | models.Q(national_id__icontains=q)
            | models.Q(phone__icontains=q)
        )
    queryset = queryset[:20]
    data = [{"id": p.id, "first_name": p.first_name, "last_name": p.last_name, "mrn": p.mrn} for p in queryset]
    return Response(data)


@api_view(["GET"])
@permission_classes([IsAuthenticated])
def api_staff_search(request):
    """
    Standalone staff search API endpoint.

    Used by survey manual send form to search for staff.
    URL: /api/staffs/search/?q=<query>&active=true
    """
    q = request.query_params.get("q", "").strip()
    queryset = Staff.objects.filter(status="active")

    # Filter by user's hospital if not admin
    user = request.user
    if hasattr(user, "hospital") and user.hospital and not user.is_superuser:
        queryset = queryset.filter(hospital=user.hospital)

    if q:
        queryset = queryset.filter(
            models.Q(first_name__icontains=q)
            | models.Q(last_name__icontains=q)
            | models.Q(name__icontains=q)
            | models.Q(name_ar__icontains=q)
            | models.Q(employee_id__icontains=q)
        )
    queryset = queryset[:20]
    data = [
        {"id": s.id, "first_name": s.first_name, "last_name": s.last_name, "employee_id": s.employee_id}
        for s in queryset
    ]
    return Response(data)
