from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
from django.db.models import Q
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages

from .models import Department, Hospital, Organization, Patient, Staff
from .forms import StaffForm


@login_required
def hospital_list(request):
    """Hospitals list view"""
    queryset = Hospital.objects.all()

    # Apply RBAC filters
    user = request.user
    if not user.is_px_admin() and user.hospital:
        queryset = queryset.filter(id=user.hospital.id)

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

    # Search
    search_query = request.GET.get('search')
    if search_query:
        queryset = queryset.filter(
            Q(name__icontains=search_query) |
            Q(name_ar__icontains=search_query) |
            Q(code__icontains=search_query)
        )

    # Ordering
    queryset = queryset.order_by('name')

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

    context = {
        'page_obj': page_obj,
        'hospitals': page_obj.object_list,
        'filters': request.GET,
    }

    return render(request, 'organizations/hospital_list.html', context)


@login_required
def department_list(request):
    """Departments list view"""
    queryset = Department.objects.select_related('hospital', 'manager')

    # Apply RBAC filters
    user = request.user
    if 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)

    status_filter = request.GET.get('status')
    if status_filter:
        queryset = queryset.filter(status=status_filter)

    # Search
    search_query = request.GET.get('search')
    if search_query:
        queryset = queryset.filter(
            Q(name__icontains=search_query) |
            Q(name_ar__icontains=search_query) |
            Q(code__icontains=search_query)
        )

    # Ordering
    queryset = queryset.order_by('hospital', 'name')

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

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

    context = {
        'page_obj': page_obj,
        'departments': page_obj.object_list,
        'hospitals': hospitals,
        'filters': request.GET,
    }

    return render(request, 'organizations/department_list.html', context)


@login_required
def staff_list(request):
    """Staff list view"""
    queryset = Staff.objects.select_related('hospital', 'department', 'user')

    # Apply RBAC filters
    user = request.user
    if 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)

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

    status_filter = request.GET.get('status')
    if status_filter:
        queryset = queryset.filter(status=status_filter)

    staff_type_filter = request.GET.get('staff_type')
    if staff_type_filter:
        queryset = queryset.filter(staff_type=staff_type_filter)

    # Search
    search_query = request.GET.get('search')
    if search_query:
        queryset = queryset.filter(
            Q(first_name__icontains=search_query) |
            Q(last_name__icontains=search_query) |
            Q(employee_id__icontains=search_query) |
            Q(license_number__icontains=search_query) |
            Q(specialization__icontains=search_query) |
            Q(job_title__icontains=search_query)
        )

    # Ordering
    queryset = queryset.order_by('last_name', 'first_name')

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

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

    context = {
        'page_obj': page_obj,
        'staff': page_obj.object_list,
        'hospitals': hospitals,
        'filters': request.GET,
    }

    return render(request, 'organizations/staff_list.html', context)


@login_required
def organization_list(request):
    """Organizations list view"""
    queryset = Organization.objects.all()

    # Apply RBAC filters
    user = request.user
    if not user.is_px_admin() and user.hospital and user.hospital.organization:
        queryset = queryset.filter(id=user.hospital.organization.id)

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

    city_filter = request.GET.get('city')
    if city_filter:
        queryset = queryset.filter(city__icontains=city_filter)

    # Search
    search_query = request.GET.get('search')
    if search_query:
        queryset = queryset.filter(
            Q(name__icontains=search_query) |
            Q(name_ar__icontains=search_query) |
            Q(code__icontains=search_query) |
            Q(license_number__icontains=search_query)
        )

    # Ordering
    queryset = queryset.order_by('name')

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

    context = {
        'page_obj': page_obj,
        'organizations': page_obj.object_list,
        'filters': request.GET,
    }

    return render(request, 'organizations/organization_list.html', context)


@login_required
def organization_detail(request, pk):
    """Organization detail view"""
    organization = Organization.objects.get(pk=pk)

    # Apply RBAC filters
    user = request.user
    if not user.is_px_admin():
        if user.hospital and user.hospital.organization:
            if organization.id != user.hospital.organization.id:
                # User doesn't have access to this organization
                from django.http import HttpResponseForbidden
                return HttpResponseForbidden("You don't have permission to view this organization")
        else:
            from django.http import HttpResponseForbidden
            return HttpResponseForbidden("You don't have permission to view this organization")

    hospitals = organization.hospitals.all()

    context = {
        'organization': organization,
        'hospitals': hospitals,
    }

    return render(request, 'organizations/organization_detail.html', context)


@login_required
def organization_create(request):
    """Create organization view"""
    # Only PX Admins can create organizations
    user = request.user
    if not user.is_px_admin():
        from django.http import HttpResponseForbidden
        return HttpResponseForbidden("Only PX Admins can create organizations")

    if request.method == 'POST':
        name = request.POST.get('name')
        name_ar = request.POST.get('name_ar')
        code = request.POST.get('code')
        address = request.POST.get('address', '')
        city = request.POST.get('city', '')
        phone = request.POST.get('phone', '')
        email = request.POST.get('email', '')
        website = request.POST.get('website', '')
        license_number = request.POST.get('license_number', '')
        status = request.POST.get('status', 'active')

        if name and code:
            organization = Organization.objects.create(
                name=name,
                name_ar=name_ar or name,
                code=code,
                address=address,
                city=city,
                phone=phone,
                email=email,
                website=website,
                license_number=license_number,
                status=status
            )

            # Redirect to organization detail
            from django.shortcuts import redirect
            return redirect('organizations:organization_detail', pk=organization.id)

    return render(request, 'organizations/organization_form.html')


@login_required
def patient_list(request):
    """Patients list view"""
    queryset = Patient.objects.select_related('primary_hospital')

    # Apply RBAC filters
    user = request.user
    if not user.is_px_admin() and user.hospital:
        queryset = queryset.filter(primary_hospital=user.hospital)

    # Apply filters
    hospital_filter = request.GET.get('hospital')
    if hospital_filter:
        queryset = queryset.filter(primary_hospital_id=hospital_filter)

    status_filter = request.GET.get('status')
    if status_filter:
        queryset = queryset.filter(status=status_filter)

    # Search
    search_query = request.GET.get('search')
    if search_query:
        queryset = queryset.filter(
            Q(mrn__icontains=search_query) |
            Q(first_name__icontains=search_query) |
            Q(last_name__icontains=search_query) |
            Q(national_id__icontains=search_query) |
            Q(phone__icontains=search_query)
        )

    # Ordering
    queryset = queryset.order_by('last_name', 'first_name')

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

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

    context = {
        'page_obj': page_obj,
        'patients': page_obj.object_list,
        'hospitals': hospitals,
        'filters': request.GET,
    }

    return render(request, 'organizations/patient_list.html', context)


@login_required
def staff_detail(request, pk):
    """Staff detail view"""
    staff = get_object_or_404(Staff.objects.select_related('user', 'hospital', 'department'), pk=pk)
    
    # Apply RBAC filters
    user = request.user
    if not user.is_px_admin() and staff.hospital != user.hospital:
        from django.http import HttpResponseForbidden
        return HttpResponseForbidden("You don't have permission to view this staff member")
    
    context = {
        'staff': staff,
    }
    
    return render(request, 'organizations/staff_detail.html', context)


@login_required
def staff_create(request):
    """Create staff view"""
    # Only PX Admins and Hospital Admins can create staff
    user = request.user
    if not user.is_px_admin() and not user.is_hospital_admin():
        from django.http import HttpResponseForbidden
        return HttpResponseForbidden("You don't have permission to create staff")
    
    if request.method == 'POST':
        form = StaffForm(request.POST)
        if form.is_valid():
            staff = form.save(commit=False)
            
            # Handle user account creation
            create_user = request.POST.get('create_user') == 'on'
            if create_user and not staff.user and staff.email:
                from .services import StaffService
                try:
                    role = StaffService.get_staff_type_role(staff.staff_type)
                    user_account = StaffService.create_user_for_staff(
                        staff, 
                        role=role, 
                        request=request
                    )
                    # Generate password for email
                    password = StaffService.generate_password()
                    user_account.set_password(password)
                    user_account.save()
                    try:
                        StaffService.send_credentials_email(staff, password, request)
                        messages.success(request, 'Staff member created and credentials email sent successfully.')
                    except Exception as e:
                        messages.warning(request, f'Staff member created but email sending failed: {str(e)}')
                except Exception as e:
                    messages.error(request, f'Staff member created but user account creation failed: {str(e)}')
            
            staff.save()
            
            # Send invitation email if requested
            if create_user and staff.user and request.POST.get('send_email') != 'false':
                from .services import StaffService
                try:
                    password = StaffService.generate_password()
                    staff.user.set_password(password)
                    staff.user.save()
                    StaffService.send_credentials_email(staff, password, request)
                    messages.success(request, 'Credentials email sent successfully.')
                except Exception as e:
                    messages.warning(request, f'Email sending failed: {str(e)}')
            
            messages.success(request, 'Staff member created successfully.')
            return redirect('organizations:staff_detail', pk=staff.id)
    else:
        form = StaffForm(user=request.user)
    
    context = {
        'form': form,
    }
    
    return render(request, 'organizations/staff_form.html', context)


@login_required
def staff_update(request, pk):
    """Update staff view"""
    staff = get_object_or_404(Staff.objects.select_related('user'), pk=pk)
    
    # Apply RBAC filters
    user = request.user
    if not user.is_px_admin() and not user.is_hospital_admin():
        from django.http import HttpResponseForbidden
        return HttpResponseForbidden("You don't have permission to update this staff member")
    
    if user.is_hospital_admin() and staff.hospital != user.hospital:
        from django.http import HttpResponseForbidden
        return HttpResponseForbidden("You don't have permission to update this staff member")
    
    if request.method == 'POST':
        form = StaffForm(request.POST, instance=staff)
        if form.is_valid():
            staff = form.save(commit=False)
            
            # Handle user account creation
            create_user = request.POST.get('create_user') == 'on'
            if create_user and not staff.user and staff.email:
                from .services import StaffService
                try:
                    role = StaffService.get_staff_type_role(staff.staff_type)
                    user_account = StaffService.create_user_for_staff(
                        staff, 
                        role=role, 
                        request=request
                    )
                    # Generate password for email
                    password = StaffService.generate_password()
                    user_account.set_password(password)
                    user_account.save()
                    try:
                        StaffService.send_credentials_email(staff, password, request)
                        messages.success(request, 'User account created and credentials email sent.')
                    except Exception as e:
                        messages.warning(request, f'User account created but email sending failed: {str(e)}')
                except Exception as e:
                    messages.error(request, f'User account creation failed: {str(e)}')
            
            staff.save()
            
            messages.success(request, 'Staff member updated successfully.')
            return redirect('organizations:staff_detail', pk=staff.id)
    else:
        form = StaffForm(instance=staff, user=request.user)
    
    context = {
        'form': form,
        'staff': staff,
    }
    
    return render(request, 'organizations/staff_form.html', context)


@login_required
def staff_hierarchy(request):
    """
    Staff hierarchy tree view
    Shows organizational structure based on report_to relationships
    """
    queryset = Staff.objects.select_related('hospital', 'department', 'report_to')
    
    # Apply RBAC filters
    user = request.user
    if 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)
    
    department_filter = request.GET.get('department')
    if department_filter:
        queryset = queryset.filter(department_id=department_filter)
    
    # Search functionality
    search_query = request.GET.get('search')
    search_result = None
    if search_query:
        try:
            search_result = Staff.objects.get(
                Q(employee_id__iexact=search_query) |
                Q(first_name__icontains=search_query) |
                Q(last_name__icontains=search_query)
            )
            # If search result exists and user has access, start hierarchy from that staff
            if search_result and (user.is_px_admin() or search_result.hospital == user.hospital):
                queryset = Staff.objects.filter(
                    Q(id=search_result.id) |
                    Q(hospital=search_result.hospital)
                )
        except Staff.DoesNotExist:
            pass
    
    # Build hierarchy structure
    def build_hierarchy(staff_list, parent=None, level=0):
        """Recursively build hierarchy tree"""
        result = []
        for staff in staff_list:
            if staff.report_to == parent:
                node = {
                    'staff': staff,
                    'level': level,
                    'direct_reports': build_hierarchy(staff_list, staff, level + 1),
                    'has_children': bool(staff.direct_reports.exists())
                }
                result.append(node)
        return result
    
    # Get all staff for the current filter
    all_staff = list(queryset)
    
    # If searching, build hierarchy from search result up
    if search_result:
        # Get all managers up the chain
        manager_chain = []
        current = search_result.report_to
        while current:
            if current in all_staff:
                manager_chain.insert(0, current)
            current = current.report_to
        
        # Add search result to chain
        if search_result not in manager_chain:
            manager_chain.append(search_result)
        
        # Build hierarchy for managers and their reports
        hierarchy = build_hierarchy(all_staff, parent=None)
        
        # Find and highlight search result
        def find_and_mark(node, target_id, path=None):
            if path is None:
                path = []
            if node['staff'].id == target_id:
                node['is_search_result'] = True
                node['search_path'] = path + [node['staff'].id]
                return node
            for child in node['direct_reports']:
                result = find_and_mark(child, target_id, path + [node['staff'].id])
                if result:
                    return result
            return None
        
        search_result_node = None
        for root in hierarchy:
            result = find_and_mark(root, search_result.id)
            if result:
                search_result_node = result
                break
    else:
        # Build hierarchy starting from top-level (no report_to)
        hierarchy = build_hierarchy(all_staff, parent=None)
    
    # Get hospitals for filter
    hospitals = Hospital.objects.filter(status='active')
    if not user.is_px_admin() and user.hospital:
        hospitals = hospitals.filter(id=user.hospital.id)
    
    # Get departments for filter
    departments = Department.objects.filter(status='active')
    if not user.is_px_admin() and user.hospital:
        departments = departments.filter(hospital=user.hospital)
    
    # Calculate statistics
    total_staff = queryset.count()
    top_managers = len(hierarchy)
    
    context = {
        'hierarchy': hierarchy,
        'hospitals': hospitals,
        'departments': departments,
        'filters': request.GET,
        'total_staff': total_staff,
        'top_managers': top_managers,
        'search_result': search_result,
    }
    
    return render(request, 'organizations/staff_hierarchy.html', context)


@login_required
def staff_hierarchy_d3(request):
    """
    Staff hierarchy D3 visualization view
    Shows interactive organizational chart using D3.js
    """
    # Get hospitals for filter (used by client-side filters)
    hospitals = Hospital.objects.filter(status='active')
    user = request.user
    if not user.is_px_admin() and user.hospital:
        hospitals = hospitals.filter(id=user.hospital.id)
    
    context = {
        'hospitals': hospitals,
    }
    
    return render(request, 'organizations/staff_hierarchy_d3.html', context)
