# Standard library imports
import json
import threading
import calendar
from datetime import datetime, timedelta
from collections import defaultdict
import ast
from django.db.models import F, Func


# Django core imports
from django.conf import settings
from django.contrib import messages
from django.contrib.auth import (
    authenticate, login, logout, update_session_auth_hash
)


from django.db.models import Count, Q, F, Q, ExpressionWrapper, IntegerField
from collections import defaultdict
from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.auth.forms import PasswordChangeForm
from django.core.exceptions import ValidationError
from django.core.mail import EmailMultiAlternatives, send_mail
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.core.validators import validate_email
from django.db import transaction
from django.db.models import (
    Q, Count, Sum, Prefetch, Value
)


from django.db.models.functions import Coalesce
from django.http import JsonResponse, Http404
from django.shortcuts import render, redirect, get_object_or_404
from django.template.loader import render_to_string
from django.utils import timezone
from django.utils.html import strip_tags
from django.utils.text import slugify
from django.utils.translation import gettext as _
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.views.decorators.http import (
    require_http_methods, require_POST, require_GET
)
from django.contrib.postgres.search import (
    SearchVector, SearchQuery, SearchRank
)

# Local imports
from .models import (
    Blog, BlogCategory, Author, Topics, Contact, Poll, Option, Vote,
    Subscriber, SiteAnalytics, AuthorAnalytics, BlogAnalytics, Task,
    TeamMember, NewsletterTask, BlogView, Issue, IssueItem
)
from .forms import (
    BlogCategoryForm, BlogForm, AuthorForm, TopicsForm, ContactForm,
    SubscriberForm, TeamMemberForm, PollForm, OptionFormSet,
    AuthorLookupForm, AuthorSubmitForm, BlogSubmitForm,
    IssueForm, IssueItemForm, IssueItemUpdateForm,
    AddBlogsToIssueForm, IssueStatusUpdateForm, TaskForm
)
from .utils import extract_superscripts, html_to_plain_text, process_footnotes
from .seoutils import StanzaSEOMetadataExtractor

# Initialize SEO metadata extractor
extractor = StanzaSEOMetadataExtractor(use_cache=True)
from .permissions import superuser_required, permission_required

from .stopwords import GENERAL_META_KEYWORDS, GENERAL_META_DESCRIPTION
from .utils import get_meta_contents

from .analytics import track_blog_view, track_page_view, update_analytics


# BlogCategory Views
@login_required
@permission_required('mimansha_main.view_blogcategory')
def blog_category_list(request):
    context = {'contents': BlogCategory.objects.all()}
    return render(request, 'mimansha_main/blog_category/blog_category_list.html', context)


@login_required
@permission_required('mimansha_main.add_blogcategory')
def blog_category_create(request):
    if request.method == 'POST':
        form = BlogCategoryForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('mimansha_main:blog_category_list')
    else:
        form = BlogCategoryForm()
    return render(request, 'mimansha_main/blog_category/blog_category_create.html', {'form': form})

@login_required
@permission_required('mimansha_main.change_blogcategory')
def blog_category_update(request, pk):
    context = get_object_or_404(BlogCategory, pk=pk)
    if request.method == 'POST':
        form = BlogCategoryForm(request.POST, request.FILES, instance=context)
        if form.is_valid():
            form.save()
            return redirect('mimansha_main:blog_category_list')
    else:
        form = BlogCategoryForm(instance=context)
    return render(request, 'mimansha_main/blog_category/blog_category_create.html', {'form': form})


@login_required
@permission_required('mimansha_main.delete_blogcategory')
def blog_category_delete(request, pk):
    context = get_object_or_404(BlogCategory, pk=pk)
    if request.method == 'POST':
        context.delete()
        return redirect('mimansha_main:blog_category_list')



# Blog Views
@login_required
@permission_required('mimansha_main.view_blog')
def blog_list(request, status=None):
    status_mapping = {
        'published': Blog.Status.PUBLISHED,
        'drafts': Blog.Status.DRAFT,
        'user-submitted': Blog.Status.USER_SUBMITTED,
        'archived': Blog.Status.ARCHIVED,
  
    }
    
    page_titles = {
        'published': 'Published Blogs',
        'drafts': 'Draft Blogs',
        'user-submitted': 'User Submitted Blogs',
        'archived': 'Archived Blogs',
    }
    
    status_value = status_mapping.get(status, Blog.Status.PUBLISHED)
    search_query = request.GET.get('search', '')

    blogs = Blog.objects.filter(status=status_value).annotate(
    total_views=Count('views')  # Count all view records (not unique IPs)
        ).order_by('-total_views', '-published_time')
    
    if search_query:
        blogs = blogs.filter(
            Q(title__icontains=search_query) |
            Q(content__icontains=search_query) |
            Q(authors__name__icontains=search_query)
        ).distinct()
    
    paginator = Paginator(blogs, 15)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    context = {
        'contents': page_obj,
        'page_title': page_titles.get(status, 'Blog Management'),
        'published_count': Blog.objects.filter(status=Blog.Status.PUBLISHED).count(),
        'author_count': Blog.objects.values('authors').distinct().count(),
        'search_query': search_query,
    }
    return render(request, 'mimansha_main/blog/blog_list.html', context)

@login_required
@permission_required('mimansha_main.add_blog')
def blog_create(request):
    if request.method == 'POST':
        form = BlogForm(request.POST, request.FILES)
        if form.is_valid():
            safe_content = html_to_plain_text(form.cleaned_data['content'])
            
            blog = form.save(commit=False)
            # Add meta fields before saving
            blog.meta_title = form.cleaned_data['title']
            blog.meta_keywords = extractor.get_metadata(safe_content)['meta_keywords']
            blog.meta_description = safe_content.replace('\n', ' ').replace('\r', ' ')[:550]
            blog.save()
            return redirect('mimansha_main:blog_list')
    else:
        form = BlogForm()
    return render(request, 'mimansha_main/blog/blog_create.html', {'form': form})

@login_required
@permission_required('mimansha_main.change_blog')
def blog_update(request, pk):
    blog = get_object_or_404(Blog, pk=pk)
    if request.method == 'POST':
        form = BlogForm(request.POST, request.FILES, instance=blog)
        if form.is_valid():
            safe_content = html_to_plain_text(form.cleaned_data['content'])
            
            blog = form.save(commit=False)
            # Add meta fields before saving
            blog.meta_title = form.cleaned_data['title']
            
            # Only set meta_keywords if it's empty or None
            if not blog.meta_keywords:
                blog.meta_keywords = extractor.get_metadata(safe_content)['meta_keywords']
            
            # Only set meta_description if it's empty or None
            if not blog.meta_description:
                blog.meta_description = safe_content.replace('\n', ' ').replace('\r', ' ')[:450]
            
            blog.save()

            return redirect('mimansha_main:blog_list')
    else:
        form = BlogForm(instance=blog)
    return render(request, 'mimansha_main/blog/blog_create.html', {'form': form})

@login_required
@permission_required('mimansha_main.delete_blog')
def blog_delete(request, pk):
    context = get_object_or_404(Blog, pk=pk)
    if request.method == 'POST':
        context.delete()
        return redirect('mimansha_main:blog_published')



# Author Views

@login_required
@permission_required('mimansha_main.view_author')
def author_list(request):
    # Get search query if present
    search_query = request.GET.get('search', '')
    
    # Filter authors based on search query
    if search_query:
        # Case-insensitive search on author name
        authors = Author.objects.filter(name__icontains=search_query).order_by('name')
    else:
        # Get all authors sorted alphabetically by name
        authors = Author.objects.all().order_by('name')
    
    # Set up pagination
    page = request.GET.get('page', 1)
    paginator = Paginator(authors, 10)  # Show 10 authors per page
    
    try:
        contents = paginator.page(page)
    except PageNotAnInteger:
        # If page is not an integer, deliver first page
        contents = paginator.page(1)
    except EmptyPage:
        # If page is out of range, deliver last page of results
        contents = paginator.page(paginator.num_pages)
    
    context = {
        'contents': contents,
        'search_query': search_query,
    }
    
    return render(request, 'mimansha_main/author/author_list.html', context)

@login_required
@permission_required('mimansha_main.add_author')
def author_create(request):
    if request.method == 'POST':
        form = AuthorForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            
            # Check which button was clicked
            if request.POST.get('submit') == 'save_and_add':
                messages.success(request, 'Author successfully created. You can now add another.')
                return redirect('mimansha_main:author_create')  # Make sure this URL name is correct
            else:
                messages.success(request, 'Author successfully created!')
                return redirect('mimansha_main:author_list')  # Make sure this URL name is correct
    else:
        form = AuthorForm()
    
    return render(request, 'mimansha_main/author/author_create.html', {
        'form': form,
    })

@login_required
@permission_required('mimansha_main.change_author')
def author_update(request, pk):
    author = get_object_or_404(Author, pk=pk)
    
    if request.method == 'POST':
        form = AuthorForm(request.POST, request.FILES, instance=author)
        if form.is_valid():
            form.save()
            
            # Check which button was clicked
            if request.POST.get('submit') == 'save_and_add':
                messages.success(request, f'Author "{author.name}" successfully updated. You can now add another.')
                return redirect('mimansha_main:author_create')
            else:
                messages.success(request, f'Author "{author.name}" successfully updated!')
                return redirect('mimansha_main:author_list')
    else:
        form = AuthorForm(instance=author)
    
    return render(request, 'mimansha_main/author/author_create.html', {
        'form': form,
        'author': author,
    })

@login_required
@permission_required('mimansha_main.delete_author')
def author_delete(request, pk):
    context = get_object_or_404(Author, pk=pk)
    if request.method == 'POST':
        context.delete()
        return redirect('mimansha_main:author_list')



# Topics Views

@login_required
@permission_required('mimansha_main.view_topics')
def topics_list(request):
    search_query = request.GET.get('search', '')
    
    # Filter topics by search query and order alphabetically by title
    topics = Topics.objects.filter(title__icontains=search_query).order_by('title')
    
    # Paginate with 30 topics per page
    paginator = Paginator(topics, 30)
    page_number = request.GET.get('page')
    topics_page = paginator.get_page(page_number)

    # Get all user IDs from topics
    user_ids = [topic.user for topic in topics if topic.user > 0]
    
    # Fetch users in one query
    from django.contrib.auth import get_user_model
    User = get_user_model()
    users = User.objects.filter(id__in=user_ids).in_bulk()
    
    return render(request, 'mimansha_main/topics/topics_list.html', {
        'topics': topics_page,
        'search_query': search_query,
        'users_dict': users,
    })

@login_required
@permission_required('mimansha_main.add_topics')
def topics_create(request):
    if request.method == 'POST':
        form = TopicsForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            
            # Check which button was clicked
            if 'save_and_add' in request.POST:
                # Return to the same form for adding another topic
                form = TopicsForm()  # Reset the form
                return render(request, 'mimansha_main/topics/topics_create.html', {
                    'form': form,
                    'success_message': 'Topic saved successfully. You can add another one.'
                })
            else:
                # Redirect to topics list if "Save" was clicked
                return redirect('mimansha_main:topics_list')
    else:
        form = TopicsForm()
    
    return render(request, 'mimansha_main/topics/topics_create.html', {'form': form})

@login_required
@permission_required('mimansha_main.change_topics')
def topics_update(request, pk):
    context = get_object_or_404(Topics, pk=pk)
    if request.method == 'POST':
        form = TopicsForm(request.POST, request.FILES, instance=context)
        if form.is_valid():
            form.save()
            return redirect('mimansha_main:topics_list')
    else:
        form = TopicsForm(instance=context)
    return render(request, 'mimansha_main/topics/topics_create.html', {'form': form})

@login_required
@permission_required('mimansha_main.delete_topics')
def topics_delete(request, pk):
    context = get_object_or_404(Topics, pk=pk)
    if request.method == 'POST':
        context.delete()
        return redirect('mimansha_main:topics_list')



# TeamMember Views
@login_required
@permission_required('mimansha_main.add_teammember')
@permission_required('mimansha_main.change_teammember')
def create_update_team_member(request, team_member_id=None):
    team_member = get_object_or_404(TeamMember, id=team_member_id) if team_member_id else None

    if request.method == 'POST':
        form = TeamMemberForm(request.POST, request.FILES, instance=team_member)
        if form.is_valid():
            form.save()
            messages.success(request, "Team member saved successfully. Redirecting to team list page...")
            return redirect('mimansha_main:team_list')
        else:
            messages.error(request, "There were errors in the form. Please fix them and try again.")
            return render(request, 'mimansha_main/teammember/team_create.html', {
                'form': form,
                'team_member_id': team_member_id,
            })
    else:
        form = TeamMemberForm(instance=team_member)
        return render(request, 'mimansha_main/teammember/team_create.html', {
            'form': form,
            'team_member_id': team_member_id,
        })

@login_required
@permission_required('mimansha_main.view_teammember')
def team_list(request):
    search_query = request.GET.get('search', '')
    team_members = TeamMember.objects.filter(name__icontains=search_query) if search_query else TeamMember.objects.all()
    paginator = Paginator(team_members, 12)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    return render(request, 'mimansha_main/teammember/team_list.html', {
        'team_members': page_obj,
        'search_query': search_query,
    })

@login_required
@permission_required('mimansha_main.delete_teammember')
def team_delete(request, pk):
    team_member = get_object_or_404(TeamMember, pk=pk)
    if request.method == 'POST':
        team_member.delete()
        if request.headers.get('x-requested-with') == 'XMLHttpRequest':
            return JsonResponse({'success': True, 'message': 'Team member deleted successfully'})
        messages.success(request, 'Team member deleted successfully')
        return redirect('mimansha_main:team_list')
    messages.error(request, 'Invalid request method')
    return redirect('mimansha_main:team_list')




# Poll Views
@login_required
@permission_required('mimansha_main.add_poll')
def create_poll(request, poll_id=None):
    poll = get_object_or_404(Poll, id=poll_id) if poll_id else None
    options = Option.objects.filter(poll=poll) if poll else []

    if request.method == 'POST':
        poll_form = PollForm(request.POST, instance=poll)
        if poll_form.is_valid():
            poll = poll_form.save()
            if poll_id:
                Option.objects.filter(poll=poll).delete()
            options_data = [request.POST.get(f'option_text_{i}') for i in range(len(request.POST) - 2)]
            for option_text in options_data:
                if option_text:
                    Option.objects.create(poll=poll, option_text=option_text)
            return JsonResponse({'success': True})
        return JsonResponse({'success': False, 'error': 'Invalid form data'})
    else:
        poll_form = PollForm(instance=poll)
        initial_options = [{'option_text': option.option_text} for option in options]
        return render(request, 'mimansha_main/polls/create_poll.html', {
            'poll_form': poll_form,
            'initial_options': initial_options,
            'poll_id': poll_id,
        })

@login_required
@permission_required('mimansha_main.delete_poll')
def poll_delete(request, pk):
    context = get_object_or_404(Poll, pk=pk)
    if request.method == 'POST':
        context.delete()
        return redirect('mimansha_main:all_polls')

from django.shortcuts import render
from django.contrib.auth.decorators import login_required, permission_required
from django.db.models import Sum # Q for complex lookups if needed
import json
from django.utils.safestring import mark_safe
from .models import Poll # Make sure to import your Poll model (e.g., from myapp.models import Poll)

@login_required
@permission_required('mimansha_main.view_poll') # Ensure this matches your app and model
def all_polls(request):
    search_query = request.GET.get('search', '').strip()
    
    polls_queryset = Poll.objects.all() # Start with all polls

    if search_query:
        # Assuming your Poll model has a 'question_text' field
        polls_queryset = polls_queryset.filter(question__icontains=search_query)

    # Eager load related options to minimize DB queries
    # .order_by('-created_at') # Optional: order polls, e.g., by creation date
    polls_list = list(polls_queryset.select_related().prefetch_related('options'))

    poll_data_for_template = []
    grand_total_votes_accumulator = 0

    for poll_instance in polls_list:
        # Access prefetched options. No new DB query here.
        options_for_this_poll = list(poll_instance.options.all()) 
        
        current_poll_total_votes = sum(option.votes for option in options_for_this_poll)
        grand_total_votes_accumulator += current_poll_total_votes

        # 1. Prepare 'options' for direct display in cards (with percentage)
        options_with_percentage = []
        for option in options_for_this_poll:
            percentage = (option.votes / current_poll_total_votes * 100) if current_poll_total_votes > 0 else 0
            options_with_percentage.append({
                'id': option.id,
                'option_text': option.option_text, # Ensure 'option_text' is the field name
                'votes': option.votes,
                'percentage': round(percentage, 1)
            })

        # 2. Prepare 'options_json' for the JavaScript chart modal
        # This MUST be a list of simple dicts: [{'text': 'Option A', 'votes': 10}, ...]
        options_for_js_chart_data = []
        for option in options_for_this_poll:
            options_for_js_chart_data.append({
                'text': str(option.option_text), # Ensure text is string
                'votes': int(option.votes)       # Ensure votes are int
            })
        
        # Convert to JSON string and mark safe for template
        # This print statement is for debugging - check your Django console output
        # print(f"Poll ID {poll_instance.id} options_for_js_chart_data: {options_for_js_chart_data}")
        options_json_string = json.dumps(options_for_js_chart_data)
        # print(f"Poll ID {poll_instance.id} options_json_string: {options_json_string}")


        poll_data_for_template.append({
            'poll': poll_instance, # The Poll model instance
            'total_votes': current_poll_total_votes,
            'options': options_with_percentage, 
            'options_json': mark_safe(options_json_string), 
        })

    total_polls_count = len(polls_list)
    # Assuming all listed polls are 'active' for this view.
    # If you have an is_active field, you'd filter/count based on that.
    active_polls_count = total_polls_count 

    if total_polls_count > 0:
        average_votes_per_poll = grand_total_votes_accumulator / total_polls_count
    else:
        average_votes_per_poll = 0

    context = {
        'poll_data': poll_data_for_template,
        'search_query': search_query,
        'total_polls_count': total_polls_count,
        'grand_total_votes': grand_total_votes_accumulator,
        'active_polls_count': active_polls_count,
        'average_votes_per_poll': average_votes_per_poll,
    }
    
    return render(request, 'mimansha_main/polls/poll_results.html', context)




#task management

from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
from django.contrib.auth.decorators import login_required, user_passes_test
from django.core.paginator import Paginator
from django.utils.timezone import now
from .models import Task
from .forms import TaskForm


from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
from django.http import JsonResponse
from django.db.models import Count
from django.utils import timezone
from .models import Task
from .forms import TaskForm

@login_required
def task_list(request):
    # Get filter parameters
    status_filter = request.GET.get('status', '')
    priority_filter = request.GET.get('priority', '')
    
    # Base queryset
    if request.user.is_superuser:
        tasks = Task.objects.all()
    else:
        tasks = Task.objects.filter(assigned_to=request.user)

    
    # Apply filters
    if status_filter:
        tasks = tasks.filter(status=status_filter)
    if priority_filter:
        tasks = tasks.filter(priority=priority_filter)
    
    # Order by due date
    tasks = tasks.order_by('-due_date')
    
    # Pagination
    paginator = Paginator(tasks, 10)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    # Prepare status counts for superuser chart
    status_counts = {}
    if request.user.is_superuser:
        status_counts_data = Task.objects.values('status').annotate(count=Count('status'))
        status_counts = {
            'not_started': next((item['count'] for item in status_counts_data if item['status'] == 'not_started'), 0),
            'in_progress': next((item['count'] for item in status_counts_data if item['status'] == 'in_progress'), 0),
            'completed': next((item['count'] for item in status_counts_data if item['status'] == 'completed'), 0),
            'cancelled': next((item['count'] for item in status_counts_data if item['status'] == 'cancelled'), 0),
        }
    
    context = {
        'page_obj': page_obj,
        'status_choices': Task.STATUS_CHOICES,
        'priority_choices': Task.PRIORITY_CHOICES,
        'status_filter': status_filter,
        'priority_filter': priority_filter,
        'status_counts': status_counts,
    }
    
    return render(request, 'mimansha_main/tasks/task_list.html', context)

@login_required
@permission_required('mimansha_main.change_task')
def create_update_task(request, pk=None):
    # Restrict access to superusers only
    if not request.user.is_superuser:
        return redirect('mimansha_main:task_list')
    
    task = None
    if pk:
        task = get_object_or_404(Task, pk=pk)
    
    if request.method == 'POST':
        form = TaskForm(request.POST, instance=task)
        if form.is_valid():
            task = form.save(commit=False)
            task.updated_by = request.user
            task.save()
            return redirect('mimansha_main:task_list')
    else:
        form = TaskForm(instance=task)
    
    context = {
        'form': form,
        'title': 'Update Task' if task else 'Create Task',
    }
    
    return render(request, 'mimansha_main/tasks/task_form.html', context)

from django.utils import timezone
from django.http import JsonResponse
from django.contrib.auth.decorators import login_required
from .models import Task

from django.utils import timezone
from django.http import JsonResponse
from django.contrib.auth.decorators import login_required
from .models import Task

@login_required
@permission_required('mimansha_main.change_task')
def update_task_status(request):
    if request.method == 'POST' and not request.user.is_superuser:
        task_id = request.POST.get('task_id')
        status_update = request.POST.get('status_update')
        response_text = request.POST.get('response_text', '').strip()

        # Validate required fields
        if not task_id or not response_text:
            return JsonResponse({
                'success': False,
                'error': 'Task ID and response text are required'
            })

        try:
            task = Task.objects.get(id=task_id)
            
            # Check task status
            if task.status in ['completed', 'cancelled']:
                return JsonResponse({
                    'success': False, 
                    'error': 'Cannot update completed or cancelled tasks'
                })

            # Format the new response entry
            timestamp = timezone.now().strftime("%Y-%m-%d %H:%M")
    
            new_entry = f"[{timestamp}] {response_text}"
            
            # Append to existing responses using ||| separator
            if task.response_from_team:
                task.response_from_team = f"{task.response_from_team}|||{new_entry}"
            else:
                task.response_from_team = new_entry
            
            # Update status if changed and provided
            if status_update and status_update != task.status:
                task.status = status_update
            
            task.save()
            return JsonResponse({
                'success': True,
                'new_status': task.status,
                'response_count': len(task.response_from_team.split('|||'))
            })
                
        except Task.DoesNotExist:
            return JsonResponse({
                'success': False,
                'error': 'Task not found'
            })
        except Exception as e:
            return JsonResponse({
                'success': False,
                'error': f'Server error: {str(e)}'
            })
    
    return JsonResponse({
        'success': False,
        'error': 'Invalid request method or permissions'
    })


@login_required
@permission_required('mimansha_main.delete_task')
def delete_task(request, pk):
    """
    Delete a task (admin only)
    """
    task = get_object_or_404(Task, pk=pk)
    if request.method == 'POST':
        task.delete()
        messages.success(request, 'Task successfully deleted!')
        return redirect('task_list')
    
    return render(request, 'tasks/task_confirm_delete.html', {'task': task})

# Special Functionality Views
@login_required
@permission_required('mimansha_main.view_blog')
def featured_page(request):
    contents = Blog.objects.filter(feature_this=True, status=1)
    return render(request, 'mimansha_main/blog/blog_list.html', {'contents': contents})


@login_required
@permission_required('users.can_view_admin_dashboard')
def admin_dashboard(request):

    update_analytics(request)
    
    # Time periods for analytics
    today = timezone.now().date()
    last_week = today - timedelta(days=7)
    last_month = today - timedelta(days=30)
    
    # Blog statistics
    total_blogs = Blog.objects.count()
    published_blogs = Blog.objects.filter(status=Blog.Status.PUBLISHED).count()
    draft_blogs = Blog.objects.filter(status=Blog.Status.DRAFT).count()
    featured_blogs = Blog.objects.filter(feature_this=True).count()
    
    # Blog status distribution
    blog_status_counts = Blog.objects.values('status').annotate(count=Count('status')).order_by('-count')
    
    # Recent blogs
    recent_blogs = Blog.objects.order_by('-created_at')[:5]
    
    # Blog views analytics - Updated to use BlogAnalytics
    total_views = BlogAnalytics.objects.aggregate(total=Sum('views'))['total'] or 0
    today_views = BlogAnalytics.objects.filter(date=today).aggregate(total=Sum('views'))['total'] or 0
    weekly_views = BlogAnalytics.objects.filter(date__gte=last_week).aggregate(total=Sum('views'))['total'] or 0
    monthly_views = BlogAnalytics.objects.filter(date__gte=last_month).aggregate(total=Sum('views'))['total'] or 0
    
    # Unique visitors analytics
    total_unique_visitors = BlogAnalytics.objects.aggregate(total=Sum('unique_visitors'))['total'] or 0
    today_unique_visitors = BlogAnalytics.objects.filter(date=today).aggregate(total=Sum('unique_visitors'))['total'] or 0
    weekly_unique_visitors = BlogAnalytics.objects.filter(date__gte=last_week).aggregate(total=Sum('unique_visitors'))['total'] or 0
    monthly_unique_visitors = BlogAnalytics.objects.filter(date__gte=last_month).aggregate(total=Sum('unique_visitors'))['total'] or 0
    
    # Popular blogs (by views from BlogAnalytics)


    popular_blogs = Blog.objects.annotate(
    total_views=Count('views')  # No distinct=True → counts all views
    ).order_by('-total_views')[:5]
    
    # Trending blogs (most views in last 7 days)
    trending_blogs = Blog.objects.annotate(
        recent_views=Coalesce(Sum(
            'analytics__views',
            filter=Q(analytics__date__gte=last_week)
        ), 0)
    ).order_by('-recent_views')[:5]
    
    # Author statistics
    total_authors = Author.objects.count()
    verified_authors = Author.objects.filter(status=Author.AuthorStatus.VERIFIED).count()
    active_authors = Author.objects.annotate(
        blog_count=Count('blogs')
    ).filter(blog_count__gt=0).count()
    
    # Recent activities for notifications panel
    recent_activities = []
    
    # Add blog activities
    recent_blog_activities = Blog.objects.order_by('-ldm')[:3]
    for blog in recent_blog_activities:
        recent_activities.append({
            'type': 'blog',
            'title': f"Blog {'published' if blog.status == Blog.Status.PUBLISHED else 'updated'}",
            'description': f"Blog '{blog.title}' was {'published' if blog.status == Blog.Status.PUBLISHED else 'updated'}",
            'timestamp': blog.ldm
        })
    
    # Add subscriber activities
    new_subscribers = Subscriber.objects.order_by('-created_at')[:3]
    for sub in new_subscribers:
        recent_activities.append({
            'type': 'subscriber',
            'title': "New subscriber",
            'description': f"{sub.email} subscribed to newsletter",
            'timestamp': sub.created_at
        })
    
    # Add system activities (example)
    recent_activities.append({
        'type': 'system',
        'title': "System update",
        'description': "Database backup completed successfully",
        'timestamp': timezone.now()
    })
    
    # Add alert if there are overdue tasks
    overdue_tasks_count = Task.objects.filter(
        due_date__lt=today,
        status__in=['pending', 'in_progress']
    ).count()
    if overdue_tasks_count > 0:
        recent_activities.append({
            'type': 'alert',
            'title': "Overdue tasks",
            'description': f"You have {overdue_tasks_count} overdue tasks",
            'timestamp': timezone.now()
        })
    
    # Sort activities by timestamp (newest first)
    recent_activities.sort(key=lambda x: x['timestamp'], reverse=True)
    
    # Top authors (by blog count)
    top_authors = Author.objects.annotate(
        blog_count=Count('blogs')
    ).order_by('-blog_count')[:5]
    
    # Category statistics
    categories_with_counts = BlogCategory.objects.annotate(
        blog_count=Count('blogs')
    ).order_by('-blog_count')
    
    # Site analytics
    try:
        site_analytics = SiteAnalytics.objects.filter(date=today).first()
    except SiteAnalytics.DoesNotExist:
        site_analytics = None
    
    # Get site analytics trends
    site_analytics_weekly = SiteAnalytics.objects.filter(date__gte=last_week).order_by('date')
    site_analytics_monthly = SiteAnalytics.objects.filter(date__gte=last_month).order_by('date')
    
    # Task management
    pending_tasks = Task.objects.filter(status='pending').order_by('due_date')[:5]
    overdue_tasks = Task.objects.filter(
        due_date__lt=today,
        status__in=['pending', 'in_progress']
    ).order_by('due_date')[:5]
    
    # Recent subscribers
    recent_subscribers = Subscriber.objects.order_by('-created_at')[:5]
    total_subscribers = Subscriber.objects.count()
    
    # Recent contacts
    recent_contacts = Contact.objects.order_by('-created_at')[:5]
    
    # Poll information
    active_polls = Poll.objects.annotate(
        option_count=Count('options'),
        total_votes=Sum('options__votes')
    ).order_by('-created_at')[:3]
    
    context = {
        # Blog statistics
        'total_blogs': total_blogs,
        'published_blogs': published_blogs,
        'draft_blogs': draft_blogs,
        'featured_blogs': featured_blogs,
        'blog_status_counts': blog_status_counts,
        'recent_blogs': recent_blogs,
        
        # View analytics - Updated
        'total_views': total_views,
        'today_views': today_views,
        'weekly_views': weekly_views,
        'monthly_views': monthly_views,
        'total_unique_visitors': total_unique_visitors,
        'today_unique_visitors': today_unique_visitors,
        'weekly_unique_visitors': weekly_unique_visitors,
        'monthly_unique_visitors': monthly_unique_visitors,
        'popular_blogs': popular_blogs,
        'trending_blogs': trending_blogs,
        
        # Author statistics
        'total_authors': total_authors,
        'verified_authors': verified_authors,
        'active_authors': active_authors,
        'top_authors': top_authors,
        
        # Category statistics
        'categories_with_counts': categories_with_counts,
        
        # Site analytics
        'site_analytics': site_analytics,
        'site_analytics_weekly': site_analytics_weekly,
        'site_analytics_monthly': site_analytics_monthly,
        
        # Task management
        'pending_tasks': pending_tasks,
        'overdue_tasks': overdue_tasks,
        
        # Subscribers and contacts
        'recent_subscribers': recent_subscribers,
        'total_subscribers': total_subscribers,
        'recent_contacts': recent_contacts,
        
        # Polls
        'active_polls': active_polls,
        
        # Recent activities for notifications panel
        'recent_activities': recent_activities,
        
        # Time periods for reference
        'today': today,
        'last_week': last_week,
        'last_month': last_month,
    }
    
    return render(request, 'pages/admin_dashboard.html', context)

@csrf_exempt
def subscribe_ajax(request):
    if request.method == 'POST':
        try:
            data = json.loads(request.body)
        except json.JSONDecodeError:
            return JsonResponse({'error': 'Invalid JSON'}, status=400)

        form = SubscriberForm(data)
        if form.is_valid():
            form.save()
            return JsonResponse({'message': 'Thank you for subscribing!'}, status=200)
        return JsonResponse({'error': form.errors}, status=400)
    return JsonResponse({'error': 'Invalid request method.'}, status=405)

@csrf_exempt
def vote(request, poll_id):
    if request.method == 'POST':
        option_id = request.POST.get('option_id')
        ip_address = request.META.get('REMOTE_ADDR')

        try:
            option = Option.objects.get(id=option_id)
            if Vote.objects.filter(poll_id=poll_id, ip_address=ip_address).exists():
                return JsonResponse({
                    'status': 'error',
                    'message': 'You have already voted on this poll.'
                })

            option.votes += 1
            option.save()
            Vote.objects.create(poll_id=poll_id, ip_address=ip_address)

            options = Option.objects.filter(poll_id=poll_id)
            total_votes = sum(option.votes for option in options)
            poll_data = [{
                'id': option.id,
                'option_text': option.option_text,
                'percentage': (option.votes / total_votes) * 100 if total_votes > 0 else 0
            } for option in options]

            return JsonResponse({
                'status': 'success',
                'total_votes': total_votes,
                'poll_data': poll_data
            })
        except Option.DoesNotExist:
            return JsonResponse({
                'status': 'error',
                'message': 'Invalid option selected.'
            })
    return JsonResponse({
        'status': 'error',
        'message': 'Invalid request method.'
    })


# Authorization views

@require_http_methods(["GET", "POST"])
def login_view(request):
    # Handle AJAX email validation
    if request.headers.get('X-Requested-With') == 'XMLHttpRequest' and request.method == "POST":
        email = request.POST.get('email', '')
        try:
            validate_email(email)
            return JsonResponse({'valid': True})
        except ValidationError:
            return JsonResponse({'valid': False, 'error': 'Please enter a valid email address'})
        
    # Handle form submission
    if request.method == "POST":
        username = request.POST.get('username')
        password = request.POST.get('password')
        remember_me = request.POST.get('remember_me') == 'on'
        
        user = authenticate(request, username=username, password=password)
        
        if user is not None:
            login(request, user)
            
            # Set session expiry based on "remember me" checkbox
            if remember_me:
                # Keep session for 2 weeks (14 days)
                request.session.set_expiry(60 * 60 * 24 * 14)
            else:
                request.session.set_expiry(0)  # Session expires when browser closes
            
            # Redirect to admin dashboard or next parameter
            next_url = request.POST.get('next') 
            if next_url:
                return redirect(next_url)
            return redirect('mimansha_main:admin_dashboard')
        else:
            messages.error(request, 'Invalid email or password. Please try again.')
            context = {
                'page_title': 'Login | MIMANSHA',
                'next': request.POST.get('next', ''),
                'form': {'errors': True}  # Add form errors flag for template to use
            }
            return render(request, 'account/login.html', context)
    
    # For GET requests, show the login page
    context = {
        'page_title': 'Login | MIMANSHA',
        'next': request.GET.get('next', '')
    }
    return render(request, 'account/login.html', context)

@login_required
def logout_view(request):
    logout(request)
    messages.success(request, 'You have been successfully logged out.')
    return redirect('mimansha_main:login')



@login_required
@require_POST
def change_password_ajax(request):
    """
    Handle password change via AJAX request.
    Returns JSON response for frontend processing.
    """
    form = PasswordChangeForm(user=request.user, data=request.POST)
    
    if form.is_valid():
        user = form.save()
        # Update the session to prevent logging out the user
        update_session_auth_hash(request, user)
        return JsonResponse({
            'success': True,
            'message': 'Your password was successfully updated!'
        })
    else:
        # Collect form errors
        errors = []
        for field, error_list in form.errors.items():
            for error in error_list:
                errors.append(f"{field}: {error}")
        
        error_message = "Please fix the following errors: " + ", ".join(errors)
        return JsonResponse({
            'success': False,
            'error': error_message
        })
    


#admin_panel views
@login_required
def subscriber_list(request):
    """
    View for displaying subscribers with pagination and search functionality
    """
    # Get search query from request
    search_query = request.GET.get('search', '')
    
    # Filter subscribers based on search query if provided
    if search_query:
        subscribers_list = Subscriber.objects.filter(
            Q(name__icontains=search_query) | 
            Q(email__icontains=search_query)
        ).order_by('name')
    else:
        subscribers_list = Subscriber.objects.all().order_by('name')
    
    # Paginate the subscribers list - 20 subscribers per page
    paginator = Paginator(subscribers_list, 20)
    page = request.GET.get('page')
    
    try:
        subscribers = paginator.page(page)
    except PageNotAnInteger:
        # If page is not an integer, deliver first page
        subscribers = paginator.page(1)
    except EmptyPage:
        # If page is out of range, deliver last page of results
        subscribers = paginator.page(paginator.num_pages)
    
    context = {
        'subscribers': subscribers,
        'paginator': paginator,
    }
    
    return render(request, 'pages/subscribers.html', context)



@login_required
@permission_required('mimansha_main.view_contact')
def contact_message(request):
    """
    View for listing and searching contact submissions.
    Includes pagination with 10 contacts per page.
    """
    # Get all contacts ordered by newest first
    contacts = Contact.objects.all().order_by('-created_at')
    
    # Get search term from request
    search_term = request.GET.get('search', '')
    
    # If search term exists, filter queryset
    if search_term:
        contacts = contacts.filter(
            Q(name__icontains=search_term) | 
            Q(mail__icontains=search_term) | 
            Q(phone__icontains=search_term) |
            Q(message__icontains=search_term)
        )
    
    # Pagination - 10 contacts per page
    paginator = Paginator(contacts, 10)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    context = {
        'contacts': page_obj,
        'search_term': search_term,  # For form repopulation
    }
    
    return render(request, 'pages/contact_messages.html', context)




#Newsletter section
from django.contrib.auth.decorators import login_required, permission_required
from django.views.decorators.http import require_http_methods
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
from django.utils.html import strip_tags
from django.conf import settings
import threading

# Newsletter section

@login_required
@permission_required('mimansha_main.add_newslettertask')
@require_http_methods(["GET", "POST"])
def send_newsletter(request):
    if request.method == 'POST':
        subject = request.POST.get('subject', '').strip()
        message = request.POST.get('message', '').strip()
        
        # Validate inputs
        if not subject or not message:
            if request.headers.get('x-requested-with') == 'XMLHttpRequest':
                return JsonResponse({'error': 'Both subject and message are required!'}, status=400)
            messages.error(request, "Both subject and message are required!")
            return redirect('mimansha_main:send_newsletter')
        
        # Get active subscribers
        subscribers = Subscriber.objects.filter(is_active=True)
        total_subscribers = subscribers.count()
        
        if total_subscribers == 0:
            if request.headers.get('x-requested-with') == 'XMLHttpRequest':
                return JsonResponse({'error': 'No active subscribers to send to!'}, status=400)
            messages.warning(request, "No active subscribers to send to!")
            return redirect('mimansha_main:send_newsletter')
        
        # Create a newsletter task record
        task = NewsletterTask.objects.create(
            subject=subject,
            message=message,
            total_subscribers=total_subscribers,
            created_by=request.user
        )
        
        # Start the email sending in a separate thread
        # Remove decorators from the target function and pass user_id if needed
        email_thread = threading.Thread(
            target=send_emails_task,  # Renamed function
            args=(task.id, request.user.id)  # Pass user ID if needed for tracking
        )
        email_thread.start()
        
        if request.headers.get('x-requested-with') == 'XMLHttpRequest':
            return JsonResponse({
                'status': 'started',
                'task_id': task.id,
                'total': total_subscribers
            })
        
        messages.success(request, f"Newsletter is being sent to {total_subscribers} subscribers in the background!")
        return redirect('mimansha_main:send_newsletter')
    
    # Check for previous task results
    latest_task = NewsletterTask.objects.filter(is_completed=True).order_by('-completed_at').first()
    previous_result = None
    
    if latest_task:
        previous_result = {
            'successful': latest_task.successful_sends,
            'failed': latest_task.failed_sends,
            'total': latest_task.total_subscribers,
            'errors': latest_task.get_errors_list()[:20]  # Show first 20 errors
        }
    
    return render(request, 'pages/send_newsletter.html', {
        'subscriber_count': Subscriber.objects.filter(is_active=True).count(),
        'previous_result': previous_result
    })



def send_emails_task(task_id, user_id=None):
    """
    Background task function - sends both HTML (with featured articles) and plain text versions
    """
    task = NewsletterTask.objects.get(id=task_id)
    subscribers = Subscriber.objects.filter(is_active=True)
    successful_sends = 0
    failed_sends = 0
    errors = []

    # Get 2 featured articles
    featured_articles = Blog.objects.filter(feature_this=True).order_by('-published_time')[:2]
    
    for subscriber in subscribers:
        try:
            # HTML version with featured articles
            html_message = render_to_string('newsletter/email_template.html', {
                'subject': task.subject,
                'message': task.message,
                'subscriber': subscriber,
                'featured_articles': featured_articles,
                'unsubscribe_url': f"{settings.SITE_URL}/unsubscribe/{subscriber.id}/"
            })
            
            # Plain text version in your specified format
            plain_text_message = (
                f" {task.subject} \n\n"
                f"Hi {subscriber.name if subscriber.name else 'there'},\n\n"
                f"{strip_tags(task.message)}\n\n"
            )
            
            
            # Add footer to plain text
            plain_text_message += (
                "💬 FOLLOW US:\n"
                "Facebook: https://www.facebook.com/profile.php?id=61575508733332\n"
                "Instagram: https://instagram.com/mimamsha_2025\n"
                "LinkedIn: https://linkedin.com/company/mimamsha\n\n"
                f"© {timezone.now().year} Your Brand. All rights reserved.\n\n"
                "📩 Submit: https://mimamsha.com/submit\n"
                "📞 Contact Us: https://mimamsha.com/contact-us\n\n"
                "Kathmandu, Nepal\n"
                f"\nUnsubscribe: {settings.SITE_URL}/unsubscribe/{subscriber.id}/"
            )
            
            email = EmailMultiAlternatives(
                subject=f" {task.subject} ",  # Added stars to subject
                body=plain_text_message,
                from_email=settings.DEFAULT_FROM_EMAIL,
                to=[subscriber.email],
                reply_to=[settings.DEFAULT_FROM_EMAIL]
            )
            
            # Attach the HTML version
            email.attach_alternative(html_message, "text/html")
            
            email.send()
            successful_sends += 1
            
        except Exception as e:
            error_msg = f"{subscriber.email}: {str(e)}"
            errors.append(error_msg)
            failed_sends += 1
            task.add_error(error_msg)
        
        # Update progress periodically
        if (successful_sends + failed_sends) % 10 == 0:
            task.update_progress(successful_sends, failed_sends)
    
    # Final update
    task.update_progress(successful_sends, failed_sends)
    task.mark_completed()

@login_required
@permission_required('mimansha_main.view_newslettertask')
def newsletter_progress(request, task_id):
    try:
        task = NewsletterTask.objects.get(id=task_id)
        
        return JsonResponse({
            'completed': task.is_completed,
            'sent': task.sent_subscribers,
            'total': task.total_subscribers,
            'successful': task.successful_sends,
            'failed': task.failed_sends,
            'errors': task.get_errors_list()[:20],
            'status': task.status,
            'progress': task.get_progress_percentage()
        })
            
    except NewsletterTask.DoesNotExist:
        return JsonResponse({'error': 'Task not found'}, status=404)


#Bloog Issues Manager views
@login_required
@permission_required('mimansha_main.view_issue')
def issue_list(request):
    queryset = Issue.objects.all()
    status = request.GET.get('status')
    
    if status and status.isdigit():
        queryset = queryset.filter(status=int(status))
    
    queryset = queryset.order_by('-publication_date', '-created_at')
    
    paginator = Paginator(queryset, 20)
    page = request.GET.get('page')
    
    try:
        issues = paginator.page(page)
    except PageNotAnInteger:
        issues = paginator.page(1)
    except EmptyPage:
        issues = paginator.page(paginator.num_pages)
    
    context = {
        'issues': issues,
    }
    
    return render(request, 'issues/issue_list.html', context)

@login_required
@permission_required('mimansha_main.add_issue')
def issue_create(request):
    if request.method == 'POST':
        form = IssueForm(request.POST, request.FILES)
        if form.is_valid():
            issue = form.save()
            messages.success(request, _('Issue created successfully!'))
            return redirect('mimansha_main:issue_list')
    else:
        form = IssueForm()
    
    return render(request, 'issues/issue_form.html', {'form': form})

@login_required
@permission_required('mimansha_main.change_issue')
def issue_update(request, slug):
    issue = get_object_or_404(Issue, slug=slug)
    
    if request.method == 'POST':
        form = IssueForm(request.POST, request.FILES, instance=issue)
        if form.is_valid():
            form.save()
            messages.success(request, _('Issue updated successfully!'))
            return redirect('mimansha_main:issue_detail', slug=issue.slug)
    else:
        form = IssueForm(instance=issue)
    
    return render(request, 'issues/issue_form.html', {'form': form, 'issue': issue})

@login_required
@permission_required('mimansha_main.view_issue')
def issue_detail(request, slug):
    issue = get_object_or_404(Issue, slug=slug)
    status_form = IssueStatusUpdateForm(instance=issue)
    add_blogs_form = AddBlogsToIssueForm(issue=issue)
    
    context = {
        'issue': issue,
        'status_form': status_form,
        'add_blogs_form': add_blogs_form,
    }
    
    return render(request, 'issues/issue_detail.html', context)

@login_required
@permission_required('mimansha_main.delete_issue')
def issue_delete(request, slug):
    issue = get_object_or_404(Issue, slug=slug)
    
    if request.method == 'POST':
        issue.delete()
        messages.success(request, _('Issue deleted successfully!'))
        return redirect('mimansha_main:issue_list')


@login_required
@require_POST
@permission_required('mimansha_main.change_issue')
def update_issue_status(request, slug):
    issue = get_object_or_404(Issue, slug=slug)
    form = IssueStatusUpdateForm(request.POST, instance=issue)
    
    if form.is_valid():
        form.save()
        messages.success(request, _('Issue status updated successfully!'))
    else:
        for error in form.errors.values():
            messages.error(request, error)
    
    return redirect('mimansha_main:issue_detail', slug=issue.slug)

@login_required
@require_POST
@permission_required('mimansha_main.change_issue')
def add_blogs_to_issue(request, slug):
    issue = get_object_or_404(Issue, slug=slug)
    form = AddBlogsToIssueForm(request.POST, issue=issue)
    
    if form.is_valid():
        blogs = form.cleaned_data['blogs']
        if blogs:
            # Get the highest current order number
            last_order = IssueItem.objects.filter(issue=issue,).order_by('-order').first()
            next_order = (last_order.order + 1) if last_order else 1
            
            # Create issue items in a transaction
            with transaction.atomic():
                for idx, blog in enumerate(blogs):
                    IssueItem.objects.create(
                        issue=issue,
                        blog=blog,
                        order=next_order + idx
                    )
            
            messages.success(request, _('Successfully added %(count)d blogs to the issue.') % {
                'count': len(blogs)
            })
        else:
            messages.info(request, _('No blogs selected to add.'))
    else:
        messages.error(request, _('There was an error adding blogs to the issue.'))
    
    return redirect('mimansha_main:issue_detail', slug=issue.slug)

@login_required
@require_POST
@permission_required('mimansha_main.change_issue')
def remove_blog_from_issue(request, issue_slug, blog_id):
    issue = get_object_or_404(Issue, slug=issue_slug)
    blog = get_object_or_404(Blog, id=blog_id)
    
    try:
        issue_item = IssueItem.objects.get(issue=issue, blog=blog)
        issue_item.delete()
        messages.success(request, _('Blog removed from issue successfully.'))
    except IssueItem.DoesNotExist:
        messages.error(request, _('Blog was not part of this issue.'))
    
    return redirect('mimansha_main:issue_detail', slug=issue.slug)

@require_POST
@csrf_exempt 
@permission_required('mimansha_main.change_issue') # Only if you're having CSRF issues with the fetch API
def update_issue_item_order(request, slug):
    try:
        data = json.loads(request.body)
        order = data.get('order', [])

        print('i reached here', order)
        
        if not order:
            return JsonResponse({'success': False, 'error': 'No order provided'})
        
        # Update the order of each issue item
        for index, item_id in enumerate(order, start=1):
            try:
                item = IssueItem.objects.get(id=item_id, issue__slug=slug)
                item.order = index
                item.save()
            except IssueItem.DoesNotExist:
                continue  # Skip if item doesn't exist
                
        return JsonResponse({'success': True})
    except Exception as e:
        return JsonResponse({'success': False, 'error': str(e)}, status=400)
    



from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import Permission, Group
from django.shortcuts import render, redirect
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from .permissions import superuser_required
import json

User = get_user_model()

@login_required
@superuser_required
def permission_manager(request):
    users = User.objects.filter(is_superuser=False).order_by('first_name')
    groups = Group.objects.all().order_by('name')
    
    permissions = {}
    for perm in Permission.objects.all().select_related('content_type'):
        app_label = perm.content_type.app_label
        if app_label not in permissions:
            permissions[app_label] = []
        permissions[app_label].append({
            'id': perm.id,
            'codename': perm.codename,
            'name': perm.name
        })
    
    return render(request, 'permissions.html', {
        'users': users,
        'groups': groups,
        'permissions': permissions
    })

@login_required
@superuser_required
def get_user_permissions(request, user_id):
    try:
        user = User.objects.get(id=user_id)
        # Get both direct permissions and permissions from groups
        permissions = list(user.user_permissions.values_list('codename', flat=True))
        group_permissions = set()
        for group in user.groups.all():
            group_perms = group.permissions.values_list('codename', flat=True)
            group_permissions.update(group_perms)
        
        all_permissions = list(set(permissions + list(group_permissions)))
        user_groups = list(user.groups.values_list('id', flat=True))
        
        return JsonResponse({
            'permissions': all_permissions, 
            'direct_permissions': permissions,
            'groups': user_groups,
            'status': 'success'
        })
    except User.DoesNotExist:
        return JsonResponse({'status': 'error', 'message': 'User not found'}, status=404)

@csrf_exempt
@login_required
@superuser_required
def update_user_permissions(request):
    if request.method == 'POST':
        try:
            data = json.loads(request.body)
            user_id = data.get('user_id')
            permissions = data.get('permissions', [])
            group_ids = data.get('groups', [])
            
            user = User.objects.get(id=user_id)
            
            # Update direct permissions
            user.user_permissions.clear()
            for codename in permissions:
                try:
                    perm = Permission.objects.get(codename=codename)
                    user.user_permissions.add(perm)
                except Permission.DoesNotExist:
                    continue
            
            # Update group memberships
            user.groups.clear()
            for group_id in group_ids:
                try:
                    group = Group.objects.get(id=group_id)
                    user.groups.add(group)
                except Group.DoesNotExist:
                    continue
            
            return JsonResponse({'status': 'success'})
            
        except User.DoesNotExist:
            return JsonResponse({'status': 'error', 'message': 'User not found'}, status=404)
        except Exception as e:
            return JsonResponse({'status': 'error', 'message': str(e)}, status=500)
    
    return JsonResponse({'status': 'error', 'message': 'Invalid request method'}, status=400)

@login_required
@superuser_required
def get_group_permissions(request, group_id):
    try:
        group = Group.objects.get(id=group_id)
        permissions = list(group.permissions.values_list('codename', flat=True))
        return JsonResponse({'permissions': permissions, 'status': 'success'})
    except Group.DoesNotExist:
        return JsonResponse({'status': 'error', 'message': 'Group not found'}, status=404)

@csrf_exempt
@login_required
@superuser_required
def update_group_permissions(request):
    if request.method == 'POST':
        try:
            data = json.loads(request.body)
            group_id = data.get('group_id')
            permissions = data.get('permissions', [])
            
            if not group_id:
                # Creating a new group
                group_name = data.get('group_name', '').strip()
                if not group_name:
                    return JsonResponse({'status': 'error', 'message': 'Group name is required'}, status=400)
                
                # Check if group already exists
                if Group.objects.filter(name=group_name).exists():
                    return JsonResponse({'status': 'error', 'message': 'Group already exists'}, status=400)
                
                group = Group.objects.create(name=group_name)
            else:
                # Updating existing group
                group = Group.objects.get(id=group_id)
                
                # If name is being updated
                new_name = data.get('group_name')
                if new_name and new_name.strip() != group.name:
                    if Group.objects.filter(name=new_name.strip()).exists():
                        return JsonResponse({'status': 'error', 'message': 'Group name already exists'}, status=400)
                    group.name = new_name.strip()
                    group.save()
            
            # Update permissions
            group.permissions.clear()
            for codename in permissions:
                try:
                    perm = Permission.objects.get(codename=codename)
                    group.permissions.add(perm)
                except Permission.DoesNotExist:
                    continue
            
            return JsonResponse({'status': 'success', 'group_id': group.id, 'group_name': group.name})
            
        except Group.DoesNotExist:
            return JsonResponse({'status': 'error', 'message': 'Group not found'}, status=404)
        except Exception as e:
            return JsonResponse({'status': 'error', 'message': str(e)}, status=500)
    
    return JsonResponse({'status': 'error', 'message': 'Invalid request method'}, status=400)

@csrf_exempt
@login_required
@superuser_required
def delete_group(request, group_id):
    if request.method == 'POST':
        try:
            group = Group.objects.get(id=group_id)
            group.delete()
            return JsonResponse({'status': 'success'})
        except Group.DoesNotExist:
            return JsonResponse({'status': 'error', 'message': 'Group not found'}, status=404)
        except Exception as e:
            return JsonResponse({'status': 'error', 'message': str(e)}, status=500)
    
    return JsonResponse({'status': 'error', 'message': 'Invalid request method'}, status=400)

@login_required
@superuser_required
def get_all_groups(request):
    groups = list(Group.objects.values('id', 'name'))
    return JsonResponse({'groups': groups, 'status': 'success'})


from django.shortcuts import render
from django.db.models import Count, Sum, Q
from django.utils import timezone
from datetime import datetime, timedelta
from django.core.paginator import Paginator
from .models import PageView, Blog
from django.contrib.auth.decorators import login_required


@login_required
@superuser_required
def analytics_dashboard(request):
    # Date calculations
    today = timezone.now().date()
    last_month_date = today - timedelta(days=30)
    current_month = today.month
    current_year = today.year
    last_month = last_month_date.month
    last_month_year = last_month_date.year
    
    # Get all views count
    total_views = PageView.objects.aggregate(total=Sum('views'))['total'] or 0
    
    # Common queryset for all pages
    all_pages = PageView.objects.values('page_name').annotate(
        total_views=Sum('views'),
        unique_views=Count('ip_address', distinct=True),
        this_month_views=Sum('views', filter=Q(date__month=current_month, date__year=current_year)),
        last_month_views=Sum('views', filter=Q(date__month=last_month, date__year=last_month_year)),
    )
    
    # Calculate growth percentage
    for page in all_pages:
        last_month_views = page.get('last_month_views', 0) or 0
        this_month_views = page.get('this_month_views', 0) or 0
        if last_month_views > 0:
            page['growth'] = ((this_month_views - last_month_views) / last_month_views) * 100
        else:
            page['growth'] = 100 if this_month_views > 0 else 0
    
    # Split data into two tables
    general_pages = [p for p in all_pages if not p['page_name'].startswith('blog_')]
    blog_pages = [p for p in all_pages if p['page_name'].startswith('blog_')]
    
    # Get top blogs with view counts
    top_blogs = Blog.objects.annotate(
        total_views=Count('views')
    ).order_by('-total_views', '-published_time')[:10]
    
    # Sort by total views (descending)
    general_pages.sort(key=lambda x: x['total_views'], reverse=True)
    blog_pages.sort(key=lambda x: x['total_views'], reverse=True)
    
    # Paginate - 30 items per page
    general_paginator = Paginator(general_pages, 30)
    blog_paginator = Paginator(blog_pages, 30)
    
    page_number = request.GET.get('page')
    general_page_obj = general_paginator.get_page(page_number)
    blog_page_obj = blog_paginator.get_page(page_number)
    
    # Format dates for display
    current_month_display = today.strftime('%B %Y')
    last_month_display = last_month_date.strftime('%B %Y')
    
    context = {
        'total_views': total_views,
        'general_pages': general_page_obj,
        'blog_pages': blog_page_obj,
        'top_blogs': top_blogs,
        'current_month': current_month_display,
        'last_month': last_month_display,
    }
    return render(request, 'pages/analytics.html', context)

# Public Views
def home_page(request):

    track_page_view(request, 'Homepage')

    featured_blogs = Blog.objects.filter(feature_this=True, status=Blog.Status.PUBLISHED)
    latest_blogs = Blog.objects.filter(status=Blog.Status.PUBLISHED).order_by('-published_time')[:6]
    poll = Poll.objects.order_by('-created_at').first()
    options = Option.objects.filter(poll=poll) if poll else []

    meta_contents = get_meta_contents(
        meta_title = 'MIMAMSHA',
        meta_description= GENERAL_META_DESCRIPTION,
        meta_keywords = GENERAL_META_KEYWORDS,
    )

    return render(request, 'pages/home.html', {
        'featured_blogs': featured_blogs,
        'latest_blogs': latest_blogs,
        'poll': poll,
        'options': options,
        'meta_contents': meta_contents,
       
    })



def about_mimamsha(request):

    track_page_view(request, 'About MIMAMSHA')
    

    meta_contents = get_meta_contents(
        meta_title='About - MIMAMSHA',
        og_image="/static/images/mimamsha.png",
        twitter_image="/static/images/mimamsha.png",  # More consistent title format
    )

    return render(request, 'pages/about.html', {
        'meta_contents': meta_contents,
    })


def category_blogs(request, category_slug):


    category = get_object_or_404(BlogCategory, slug=category_slug)
    blogs = Blog.objects.filter(category=category, status=Blog.Status.PUBLISHED).order_by('-created_at')
    for blog in blogs:
        blog.generated_slug = slugify(blog.title)
    
    paginator = Paginator(blogs, 10)
    page_number = request.GET.get('page', 1)
    page_obj = paginator.get_page(page_number)

    meta_contents = get_meta_contents(
        meta_title = f'MIMAMSHA - {category}',
    )


    track_page_view(request, f'MIMAMSHA - {category}')
    
    return render(request, 'pages/categorical_blogs.html', {
        'category': category,
        'blogs': blogs,
        'page_obj': page_obj,
        'meta_contents': meta_contents,
    })



def author(request):

    track_page_view(request, 'MIMAMSHA - Authors')

    search_query = request.GET.get('search', '')
    
    # Get all verified authors ordered by name A-Z
    all_authors_qs = Author.objects.filter(status=Author.AuthorStatus.VERIFIED).order_by('name')
    
    # Filtered authors for pagination based on search query (maintains name order)
    filtered_authors = all_authors_qs
    if search_query:
        filtered_authors = all_authors_qs.filter(
            Q(name__icontains=search_query) | 
            Q(affilation__icontains=search_query) |
            Q(description__icontains=search_query)
        ).order_by('name')  # Ensure filtered results are also ordered
    
    # Set up pagination for filtered authors
    paginator = Paginator(filtered_authors, 10)  # Show 6 authors per page
    page_number = request.GET.get('page', 1)
    page_obj = paginator.get_page(page_number)
    
    # Prepare all authors for client-side filtering (already ordered by name)
    all_authors = [
        {
            'id': author_obj.id,
            'name': author_obj.name,
            'description': author_obj.description,
            'affilation': author_obj.affilation,
            'image': author_obj.image.url
        }
        for author_obj in all_authors_qs  # Already ordered by name
    ]
    
    all_authors_json = json.dumps(all_authors)

    meta_contents = get_meta_contents(
        meta_title='MIMAMSHA - Authors',
    )
    
    return render(request, 'pages/authors.html', {
        'page_obj': page_obj,  # Already ordered by name
        'search_query': search_query,
        'authors_json': page_obj.object_list.exists(),  # Boolean flag
        'all_authors_json': all_authors_json,  # All authors ordered A-Z
        'meta_contents': meta_contents,
    })


def author_blogs(request, author_id):

    author_obj = get_object_or_404(Author, id=author_id)
    blogs_list = author_obj.blogs.filter(status=Blog.Status.PUBLISHED).distinct().order_by('-published_time')
    paginator = Paginator(blogs_list, 6)
    page = request.GET.get('page')
    try:
        page_obj = paginator.page(page)
    except PageNotAnInteger:
        page_obj = paginator.page(1)
    except EmptyPage:
        page_obj = paginator.page(paginator.num_pages)

    meta_contents = get_meta_contents(
        meta_title = f'MIMAMSHA - {author_obj.name}',
        og_image = author_obj.image,
        twitter_image= author_obj.image,
        canonical_url=f"https://www.mimamsha.com/authors/author-{author_obj.id}/blogs/",
    )

    track_page_view(request, f'Author Blogs - {author_obj.name}')
    
    return render(request, 'pages/author_blogs.html', {
        'author': author_obj,
        'latest_blogs': page_obj,
        'blogs': blogs_list,
        'meta_contents': meta_contents,
    })


from django.db.models import Q, Case, When, Value, IntegerField

def topic_detail(request, slug):
    topics = Topics.objects.all()
    topic = next((t for t in topics if slugify(t.title) == slug), None)
    if not topic:
        raise Http404("Topic does not exist")
    
    # Single efficient query for PostgreSQL
    blogs = Blog.objects.filter(
        Q(topic=topic) | Q(related_topics=topic),
        status=Blog.Status.PUBLISHED
    ).annotate(
        is_exact_match=Case(
            When(topic=topic, then=Value(1)),
            default=Value(0),
            output_field=IntegerField()
        )
    ).order_by('-is_exact_match', '-published_time').distinct()
    
    paginator = Paginator(blogs, 9)
    page_number = request.GET.get('page', 1)
    page_obj = paginator.get_page(page_number)

    meta_contents = get_meta_contents(
        meta_title=f'MIMAMSHA - {topic.title}',
    )

    track_page_view(request, f'Topics - {topic.title}')

    
    return render(request, 'pages/topics_detail.html', {
        'topic': topic,
        'blogs': page_obj.object_list,  # Paginated blog list
        'page_obj': page_obj,           # Pagination object
        'meta_contents': meta_contents,
    })


from django.db.models import Count, Q
from collections import defaultdict
from django.utils.text import slugify

def explore_by_topics(request):
    # Get counts for published blogs where topic is main topic
    main_counts = (
        Blog.objects.filter(status=Blog.Status.PUBLISHED)
        .values('topic')
        .annotate(count=Count('id'))
        .order_by()
    )
    main_counts_dict = {item['topic']: item['count'] for item in main_counts}
    
    # Get counts for published blogs where topic is in related_topics
    related_counts = (
        Blog.objects.filter(
            status=Blog.Status.PUBLISHED,
            related_topics__isnull=False
        )
        .values('related_topics')
        .annotate(count=Count('id'))
        .order_by()
    )
    related_counts_dict = {item['related_topics']: item['count'] for item in related_counts}
    
    # Get all topics and build the data structure
    topics = Topics.objects.all().order_by('title')
    
    # Group by first letter (now includes all topics)
    topics_with_letters = defaultdict(list)
    for topic in topics:
        total = main_counts_dict.get(topic.id, 0) + related_counts_dict.get(topic.id, 0)
        
        first_char = topic.title[0].upper() if topic.title else '#'
        if not first_char.isalpha():
            first_char = '#'
            
        topics_with_letters[first_char].append({
            'title': topic.title,
            'slug': topic.slug if hasattr(topic, 'slug') else slugify(topic.title),
            'blog_count': total  # Will be 0 if no published blogs
        })
    
    # Ensure all letters are present
    alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ#"
    for letter in alphabet:
        if letter not in topics_with_letters:
            topics_with_letters[letter] = []
    
    # Sort the dictionary
    topics_with_letters = dict(sorted(topics_with_letters.items()))

    track_page_view(request, 'Topics')

    
    meta_contents = get_meta_contents(
        meta_title='MIMAMSHA - Topics',
    )
    
    context = {
        'topics_with_letters': topics_with_letters,
        'alphabet': alphabet,
        'has_topics': True,  # Now always True since we show all topics
        'meta_contents': meta_contents,
    }
    
    return render(request, 'pages/topics.html', context)

def explore_by_issue(request):
    issues_list = Issue.objects.filter(status=Issue.Status.PUBLISHED).order_by('-publication_date')
    
    # Pagination with 10 items per page
    page = request.GET.get('page', 1)
    paginator = Paginator(issues_list, 10)
    
    try:
        issues = paginator.page(page)
    except PageNotAnInteger:
        issues = paginator.page(1)
    except EmptyPage:
        issues = paginator.page(paginator.num_pages)
    
    meta_contents = get_meta_contents(
        meta_title = 'MIMAMSHA - Issues',
    )

    track_page_view(request, 'Issues')

    
    context = {
        'issues': issues,
        'meta_contents': meta_contents,
    }
    return render(request, 'pages/explore_by_issue.html', context)


def explore_issue_detail(request, issue_id, slug):
    """
    View function to display issue details and associated blogs
    
    Args:
        request: HTTP request object
        issue_id: ID of the Issue to display
        slug: URL slug of the Issue
        
    Returns:
        Rendered issue detail page with context
    """
    # Get the issue or return 404
    issue = get_object_or_404(Issue, id=issue_id, slug=slug)
    
    # Get all issue items for this issue, ordered by their order field
    issue_items = IssueItem.objects.filter(issue=issue).select_related('blog').order_by('order')
    
    # Separate featured and regular blogs
    featured_blogs = [item.blog for item in issue_items if item.featured]
    regular_blogs = [item.blog for item in issue_items if not item.featured]
    
    # Get related issues (other issues, excluding the current one)
    # Limit to 4 issues ordered by publication date (newest first)
    related_issues = Issue.objects.filter(
        status=Issue.Status.PUBLISHED
    ).exclude(
        id=issue.id
    ).order_by('-publication_date')[:4]

    meta_contents = get_meta_contents(
        meta_title = f'MIMAMSHA - {issue.name}',
    )
    
    track_page_view(request, f'Issue - {issue.name}')

    # Prepare context
    context = {
        'issue': issue,
        'featured_blogs': featured_blogs,
        'regular_blogs': regular_blogs,
        'related_issues': related_issues,
        'page_title': issue.name,
        'page_description': issue.description,
        'page_image': issue.cover_image.url if issue.cover_image else None,
        'meta_contents': meta_contents,
    }
    
    return render(request, 'pages/explore_issue_detail.html', context)




def team(request):
    team_members_objects = TeamMember.objects.all().order_by('name')

    team_members = [
        {
            'name': member.name,
            'role': member.role,
            'image': member.image,
            'facebook_link': member.facebook_link,
            'twitter_link': member.twitter_link,
            'insta_link': member.insta_link,
            'email': member.email,
        }
        for member in team_members_objects
    ]

    meta_contents = get_meta_contents(
        meta_title='MIMAMSHA -Team',  # More consistent title format
    )

    track_page_view(request, 'Team')


    return render(request, 'pages/team.html', {
        'meta_contents': meta_contents, 
        'team_members': team_members})

from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
from django.conf import settings
from .models import TeamMember  # Make sure to import TeamMember

def send_contact_notification(contact_instance):
    """
    Sends HTML email notification to ALL team members about a new contact enquiry.
    """
    subject = f'New Contact Enquiry: {contact_instance.name}'
    
    # Plain text version
    text_content = f"""
    You have received a new contact enquiry:
    
    Name: {contact_instance.name}
    Email: {contact_instance.mail}
    Phone: {contact_instance.phone}
    Message: {contact_instance.message}
    
    Received at: {contact_instance.created_at}
    """
    
    # HTML version
    html_content = render_to_string('newsletter/contact_notification.html', {
        'contact': contact_instance
    })
    
    # Get ALL team member emails
    recipient_list = list(TeamMember.objects.values_list('email', flat=True))
    
    if not recipient_list:
        print("No team members found in the database.")
        return
    
    try:
        email = EmailMultiAlternatives(
            subject=subject,
            body=text_content,
            from_email=settings.DEFAULT_FROM_EMAIL,
            to=recipient_list,
        )
        email.attach_alternative(html_content, "text/html")
        email.send(fail_silently=False)
        print(f"Email sent successfully to {len(recipient_list)} recipients")
    except Exception as e:
        print(f"Failed to send email: {e}")
        raise

from django.shortcuts import render, redirect
from django.contrib import messages
from threading import Thread

def send_email_async(contact_instance):
    """Helper function to send email in background"""
    try:
        send_contact_notification(contact_instance)
    except Exception as e:
        print(f"Email sending error: {e}")

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
    
                # Save the contact instance
                contact_instance = form.save()
                
                # Start email sending in background
                Thread(
                    target=send_email_async,
                    args=(contact_instance,),
                    daemon=True
                ).start()
                
                # Add success message that will persist through redirect
                messages.success(request, 'Your message has been sent successfully!')
                
                # Redirect to clear POST data and show message
                return redirect('mimansha_main:contact_us')  # Redirects back to same page
        
        else:
            # Form is invalid - return with errors
            return render(request, 'pages/contact.html', {
                'form': form,
                'meta_contents': get_meta_contents(meta_title='MIMAMSHA - Contact'),
            })
    
    # GET request or redirect after POST
    return render(request, 'pages/contact.html', {
        'form': ContactForm(),
        'meta_contents': get_meta_contents(meta_title='MIMAMSHA - Contact'),
    })


def submit_articles(request):
    # Clear any existing messages to prevent message leakage
    storage = messages.get_messages(request)
    storage.used = True  # Mark all existing messages as used

    meta_contents = get_meta_contents(
        meta_title='MIMAMSHA - Submit',
    )
    context = {
        'lookup_form': AuthorLookupForm(),
        'author_form': AuthorSubmitForm(),
        'blog_form': BlogSubmitForm(),
        'existing_author': None,
        'show_blog_form': False,
        'meta_contents': meta_contents,
    }

    if request.method == 'POST':
        # Handle author lookup
        if 'lookup_author' in request.POST:
            lookup_form = AuthorLookupForm(request.POST)
            if lookup_form.is_valid():
                phone = lookup_form.cleaned_data['phone']
                try:
                    author = Author.objects.get(phone=phone)
                    request.session['existing_author_id'] = author.id
                    messages.success(request, f"Welcome back, {author.name}!", extra_tags='submit_articles')
                    return redirect('mimansha_main:submit_articles')
                except Author.DoesNotExist:
                    messages.info(request, "No author found. Please register.", extra_tags='submit_articles')
                    context['lookup_form'] = lookup_form
            else:
                context['lookup_form'] = lookup_form

        # Handle article submission for existing author
        elif 'submit_article' in request.POST:
            author_id = request.session.get('existing_author_id')
            blog_form = BlogSubmitForm(request.POST)
            context['blog_form'] = blog_form

            try:
                with transaction.atomic():
                    if author_id:
                        author = Author.objects.get(id=author_id)
                        if blog_form.is_valid():
                            blog = blog_form.save(commit=False)
                            blog.status = Blog.Status.USER_SUBMITTED
                            blog.save()
                            blog.authors.add(author)
                            del request.session['existing_author_id']
                            messages.success(request, "Article submitted successfully!", extra_tags='submit_articles')
                            return redirect('mimansha_main:submit_articles')
                        context['show_blog_form'] = True
                        context['existing_author'] = author

                    else:
                        author_form = AuthorSubmitForm(request.POST, request.FILES)
                        context['author_form'] = author_form
                        
                        if author_form.is_valid() and blog_form.is_valid():
                            author = author_form.save(commit=False)
                            author.status = Author.AuthorStatus.USER_SUBMITTED
                            author.save()
                            
                            blog = blog_form.save(commit=False)
                            blog.status = Blog.Status.USER_SUBMITTED
                            blog.save()
                            blog.authors.add(author)
                            
                            messages.success(request, "Article and author details submitted successfully!", extra_tags='submit_articles')
                            return redirect('mimansha_main:submit_articles')
                        context['show_blog_form'] = True

            except Exception as e:
                messages.error(request, f"Submission error: {str(e)}", extra_tags='submit_articles')

        # Handle form submission for new author
        elif 'submit_new_author' in request.POST:
            author_form = AuthorSubmitForm(request.POST, request.FILES)
            context['author_form'] = author_form
            
            if author_form.is_valid():
                author = author_form.save(commit=False)
                author.status = Author.AuthorStatus.USER_SUBMITTED
                author.save()
                request.session['existing_author_id'] = author.id
                context['show_blog_form'] = True
                context['existing_author'] = author
                messages.success(request, "Author details saved. Now submit your article.", extra_tags='submit_articles')
                return redirect('mimansha_main:submit_articles')

    # Handle existing author session
    existing_author_id = request.session.get('existing_author_id')
    if existing_author_id:
        try:
            context['existing_author'] = Author.objects.get(id=existing_author_id)
            context['show_blog_form'] = True
        except Author.DoesNotExist:
            del request.session['existing_author_id']
    
    track_page_view(request, 'Submit Articles')

    return render(request, 'pages/submit_articles.html', context)


@require_http_methods(["POST"])
@csrf_protect
def clear_author_session(request):
    if 'existing_author_id' in request.session:
        del request.session['existing_author_id']
    return JsonResponse({'status': 'success'})


def search_view(request):

    """
    Advanced search view using PostgreSQL full-text search capabilities
    for more effective searching including ranking and relevance.
    
    Search results are grouped by content type for better organization.
    
    This view requires PostgreSQL as database backend and
    django.contrib.postgres in INSTALLED_APPS.
    """
    query = request.GET.get('q', '')
    page = request.GET.get('page', 1)
    results_per_page = 10
    
    if not query:
        return render(request, 'pages/search_results.html', {
            'query': query,
            'blogs': [],
            'blog_categories': [],
            'topics': [],
            
            'total_results': 0,
        })
    
    # Create search query
    search_query = SearchQuery(query)
    
    # Define search vectors for each model
    blog_vector = SearchVector('title', weight='A') + SearchVector('content', weight='B')
    category_vector = SearchVector('title', weight='A')
    
    # Search and rank results
    blogs = Blog.objects.annotate(
        rank=SearchRank(blog_vector, search_query)
    ).filter(
        rank__gt=0.1,
        status=Blog.Status.PUBLISHED
    ).order_by('-rank')

    for blog in blogs:
        blog.generated_slug = slugify(blog.title)
    
    blog_categories = BlogCategory.objects.annotate(
        rank=SearchRank(category_vector, search_query)
    ).filter(
        rank__gt=0.1,
        rskey=0  # Only active records
    ).order_by('-rank')
    
    topics = Topics.objects.annotate(
        rank=SearchRank(category_vector, search_query)
    ).filter(
        rank__gt=0.1,
        rskey=0  # Only active records
    ).order_by('-rank')
    
    
    
    # Combine all results with type and rank for sorting
    all_results = []
    for blog in blogs:
        all_results.append({'type': 'blog', 'object': blog, 'rank': blog.rank})
    for category in blog_categories:
        all_results.append({'type': 'blog_category', 'object': category, 'rank': category.rank})
    for topic in topics:
        all_results.append({'type': 'topic', 'object': topic, 'rank': topic.rank})
    
    
    # Sort by rank
    all_results.sort(key=lambda x: x['rank'], reverse=True)
    
    # Paginate results
    paginator = Paginator(all_results, results_per_page)
    try:
        paginated_results = paginator.page(page)
    except PageNotAnInteger:
        paginated_results = paginator.page(1)
    except EmptyPage:
        paginated_results = paginator.page(paginator.num_pages)
    
    # Organize results by type for template rendering
    grouped_results = defaultdict(list)
    for result in paginated_results:
        grouped_results[result['type']].append(result['object'])
    
    total_results = len(all_results)

    meta_contents = get_meta_contents(
        meta_title = 'MIMAMSHA - Search Results',
    )

    track_page_view(request, 'Search Results')

    
    return render(request, 'pages/search_results.html', {
        'query': query,
        'blogs': grouped_results.get('blog', []),
        'blog_categories': grouped_results.get('blog_category', []),
        'topics': grouped_results.get('topic', []),
        'paginated_results': paginated_results,
        'total_results': total_results,
        'meta_contents': meta_contents,
    })

@login_required
@require_GET
def search_authors(request):
    """Return authors matching the search query"""
    query = request.GET.get('term', '')
    authors = Author.objects.filter(name__icontains=query)[:10]
    results = [{'id': author.id, 'text': author.name} for author in authors]
    return JsonResponse({'results': results})


@login_required
@require_GET
def search_topics(request):
    """Return topics matching the search query"""
    query = request.GET.get('term', '')
    topics = Topics.objects.filter(title__icontains=query)[:10]
    results = [{'id': topic.id, 'text': topic.title} for topic in topics]
    return JsonResponse({'results': results})


from django.shortcuts import get_object_or_404, render
from django.db.models import Q, Case, When
import ast
from .models import Blog

def blog_detail(request, blog_id, slug):
    # Get blog details with optimized queries
    blog_details = get_object_or_404(
        Blog.objects.select_related('topic', 'category').prefetch_related('authors', 'related_topics'), 
        pk=blog_id, 
        slug=slug,
        status=Blog.Status.PUBLISHED
    )
    
    # Track view
    track_blog_view(blog_details, request)

    # Get related blogs with priority logic
    try:
        # Get the main blog's topic and related topics
        main_topic = blog_details.topic
        related_topics = blog_details.related_topics.all()
        category = blog_details.category

        # Create base query excluding the current blog
        base_query = Blog.objects.filter(
            status=Blog.Status.PUBLISHED
        ).exclude(
            pk=blog_id
        )

        # Build the prioritized query
        related_blogs = base_query.filter(
            Q(topic=main_topic) | 
            Q(topic__in=related_topics) |
            Q(category=category)
        ).distinct().order_by(
            Case(When(topic=main_topic, then=0)),
            Case(When(topic__in=related_topics, then=1)),
            Case(When(category=category, then=2)),
            '-published_time'
        )[:4]

        # If we still don't have 4 blogs, fill with any published blogs
        if len(related_blogs) < 4:
            remaining = 4 - len(related_blogs)
            additional_blogs = base_query.exclude(
                pk__in=[b.pk for b in related_blogs]
            ).order_by('-published_time')[:remaining]
            related_blogs = list(related_blogs) + list(additional_blogs)
    except Exception as e:
        # Fallback to simple query if anything goes wrong
        related_blogs = Blog.objects.filter(
            status=Blog.Status.PUBLISHED
        ).exclude(
            pk=blog_id
        ).order_by('-published_time')[:4]

    # Safely handle meta keywords
    meta_keywords = ""
    if blog_details.meta_keywords:
        try:
            if isinstance(blog_details.meta_keywords, str):
                meta_keywords_list = ast.literal_eval(blog_details.meta_keywords)
                meta_keywords = ", ".join(str(item) for item in meta_keywords_list)
            else:
                meta_keywords = ", ".join(str(item) for item in blog_details.meta_keywords)
        except (ValueError, SyntaxError, TypeError):
            pass

    meta_contents = get_meta_contents(
        meta_title=blog_details.meta_title,  
        meta_keywords=meta_keywords,
        meta_description=blog_details.meta_description,
        og_image=blog_details.meta_image,
        twitter_image=blog_details.meta_image,
        canonical_url=f"https://www.mimamsha.com/blogs/{blog_details.id}/{blog_details.slug}",
        article_published_time=blog_details.published_time.isoformat() if hasattr(blog_details, 'published_time') else None,
        article_modified_time=blog_details.ldm.isoformat() if hasattr(blog_details, 'ldm') else None,
        article_author=blog_details.author.get_full_name() if hasattr(blog_details, 'author') else None,
        article_section=blog_details.category.title if hasattr(blog_details, 'category') else None,
        article_tag=meta_keywords  # Or use specific tags if available
    )

    # Process blog content
    try:
        processed_blog = process_footnotes(blog_details.content)
    except Exception as e:
        processed_blog = {
            'processed_content': blog_details.content,
            'footnotes_template': ''
        }

    # Track page view
    try:
        track_page_view(request, f'{blog_details.title}')
    except Exception:
        pass  # Silently fail tracking if it errors

    return render(request, 'pages/blog_detail.html', {
        'blog': blog_details,
        'related_blogs': related_blogs,
        'meta_contents': meta_contents,
        'processed_content': processed_blog['processed_content'],
        'footnotes_template': processed_blog['footnotes_template'],
    })

def popular_blogs(request):
    # Get all blogs ordered by total views (not unique IPs) and then by publication time
    blogs = Blog.objects.annotate(
        total_views=Count('views')  # Count all views, not distinct IPs
    ).order_by('-total_views', '-published_time')[:10]


    # Pagination - 6 blogs per page
    paginator = Paginator(blogs, 6)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)

    meta_contents = get_meta_contents(
        meta_title='MIMAMSHA - Popular Blogs',
    )

    context = {
        'page_obj': page_obj,
        'meta_contents': meta_contents,
    }

    track_page_view(request, 'Popular Blogs')

    return render(request, 'pages/popular_blogs.html', context)