from rest_framework import status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination
from django.db import models
from posts.models import Post
from .serializers import PostSerializer, PostCreateSerializer, RecommendedPostSerializer
from likes.models import LikePost
from django.db.models import Q


def get_visible_posts(user):
    """
    Retourne les posts visibles pour un utilisateur donné selon l'audience.
    Exclut automatiquement les posts des utilisateurs bloqués ou bloqueurs.
    Gère également CLOSE_FRIENDS et les utilisateurs restreints.
    Exclut les posts qui appartiennent à un groupe (group__isnull=True).
    """
    queryset = Post.objects.filter(is_active=True, group__isnull=True)

    if user.is_authenticated:
        from users.models import BlockedUser, CloseFriend, RestrictedUser

        # Get IDs of users blocked by current user
        blocked_ids = BlockedUser.objects.filter(blocker=user).values_list('blocked_id', flat=True)
        # Get IDs of users who blocked current user
        blocked_by_ids = BlockedUser.objects.filter(blocked=user).values_list('blocker_id', flat=True)
        # Get IDs of users who have restricted current user (current user won't see their posts)
        restricted_by_ids = RestrictedUser.objects.filter(restricted=user).values_list('user_id', flat=True)

        # Exclude blocked users content and restricted content
        queryset = queryset.exclude(created_by_id__in=blocked_ids)\
                          .exclude(created_by_id__in=blocked_by_ids)\
                          .exclude(created_by_id__in=restricted_by_ids)

        # Get IDs of users who have current user in their close friends list
        close_friend_of_ids = CloseFriend.objects.filter(friend=user).values_list('user_id', flat=True)

        # Visibility rules:
        # 1. Posts de l'utilisateur lui-même (toujours visibles)
        # 2. Posts des comptes publics où audience='PUBLIC'
        # 3. Posts des comptes suivis (publics ou privés) où audience='FOLLOWERS' ou audience='PUBLIC'
        # 4. Posts avec audience='CLOSE_FRIENDS' seulement si l'utilisateur est dans la liste close friends du créateur

        return queryset.filter(
            Q(created_by=user) |
            Q(created_by__is_private=False, audience='PUBLIC') |
            Q(created_by__followers__follower=user, audience__in=['PUBLIC', 'FOLLOWERS']) |
            Q(created_by_id__in=close_friend_of_ids, audience='CLOSE_FRIENDS')
        ).distinct()
    else:
        # Uniquement les posts publics des comptes non-privés pour les anonymes
        return queryset.filter(created_by__is_private=False, audience='PUBLIC')

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def create_post(request):
    """
    Créer un post avec ou sans images
    """
    # Passer le contexte de la requête au serializer
    serializer = PostCreateSerializer(data=request.data, context={'request': request})
    if serializer.is_valid():
        post = serializer.save()

        # Notify followers who have enabled notifications for this user or category
        from notifications.utils import create_notification
        from follows.models import FollowUser, FollowCategory

        # Notify followers of the user
        user_followers = FollowUser.objects.filter(followed=request.user)
        for follow in user_followers:
            # Let create_notification handle preference checks
            create_notification(
                recipient=follow.follower,
                sender=request.user,
                notification_type='new_post_user',
                content=f'{request.user.first_name} {request.user.last_name} published a new post',
                related_post=post
            )

        # Notify followers of the category (if post has a category)
        if post.category:
            category_followers = FollowCategory.objects.filter(category=post.category)
            for follow in category_followers:
                # Don't notify self
                if follow.user != request.user:
                    # Let create_notification handle preference checks
                    create_notification(
                        recipient=follow.user,
                        sender=request.user,
                        notification_type='new_post_category',
                        content=f'New post in {post.category.title}',
                        related_post=post,
                        related_category=post.category
                    )

        return Response(PostSerializer(post, context={'request': request}).data, status=status.HTTP_201_CREATED)

    # Afficher les erreurs de validation pour le débogage
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def list_posts(request):
    posts = get_visible_posts(request.user)

    # Pagination
    paginator = PageNumberPagination()
    paginator.page_size = 20
    result_page = paginator.paginate_queryset(posts, request)

    serializer = PostSerializer(result_page, many=True, context={'request': request})
    return paginator.get_paginated_response(serializer.data)


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def post_detail(request, post_id):
    try:
        post = get_visible_posts(request.user).get(id=post_id)
        serializer = PostSerializer(post, context={'request': request})
        return Response(serializer.data)
    except Post.DoesNotExist:
        return Response({'error': 'Post not found'}, status=status.HTTP_404_NOT_FOUND)


@api_view(['PUT'])
@permission_classes([IsAuthenticated])
def update_post(request, post_id):
    """
    Mettre à jour un post (contenu et/ou images)
    """
    try:
        post = Post.objects.get(id=post_id)

        # Vérifier que l'utilisateur est le créateur du post
        if post.created_by != request.user:
            return Response({'error': 'Permission denied'}, status=status.HTTP_403_FORBIDDEN)

        # Passer le contexte au serializer
        # Note: On passe request.data directement. Le serializer gère request.FILES via le contexte.
        serializer = PostCreateSerializer(post, data=request.data, partial=True, context={'request': request})

        if serializer.is_valid():
            post = serializer.save()

            # Mettre à jour le timestamp de modification
            post.is_updated = True
            post.save()

            return Response(PostSerializer(post, context={'request': request}).data, status=status.HTTP_200_OK)

        # Afficher les erreurs de validation pour le débogage

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    except Post.DoesNotExist:
        return Response({'error': 'Post not found'}, status=status.HTTP_404_NOT_FOUND)


@api_view(['DELETE'])
@permission_classes([IsAuthenticated])
def delete_post(request, post_id):
    try:
        post = Post.objects.get(id=post_id)

        # Vérifier que l'utilisateur est le créateur du post
        if post.created_by != request.user:
            return Response({'error': 'Permission denied'}, status=status.HTTP_403_FORBIDDEN)

        # Soft delete
        post.is_active = False
        post.save()
        return Response(status=status.HTTP_204_NO_CONTENT)
    except Post.DoesNotExist:
        return Response({'error': 'Post not found'}, status=status.HTTP_404_NOT_FOUND)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def like_post(request, post_id):
    try:
        post = Post.objects.get(id=post_id, is_active=True)

        # Vérifier si les commentaires sont autorisés pour ce post
        if not post.allow_comments:
            print(f"DEBUG: create_comment 403: post.allow_comments={post.allow_comments}, post_id={post.id}")
            return Response({'error': 'Comments are not allowed for this post'}, status=status.HTTP_403_FORBIDDEN)

        # Vérifier si l'utilisateur a déjà aimé ce post
        if LikePost.objects.filter(user=request.user, post=post).exists():
            return Response({'error': 'You already liked this post'}, status=status.HTTP_400_BAD_REQUEST)

        LikePost.objects.create(user=request.user, post=post)

        # Create notification for post owner (don't notify self)
        if post.created_by != request.user:
            from notifications.utils import create_notification
            create_notification(
                recipient=post.created_by,
                sender=request.user,
                notification_type='like_post',
                content=f'{request.user.first_name} {request.user.last_name} liked your post',
                related_post=post
            )

        return Response({'message': 'Post liked successfully'}, status=status.HTTP_201_CREATED)
    except Post.DoesNotExist:
        return Response({'error': 'Post not found'}, status=status.HTTP_404_NOT_FOUND)


@api_view(['DELETE'])
@permission_classes([IsAuthenticated])
def unlike_post(request, post_id):
    try:
        post = Post.objects.get(id=post_id, is_active=True)
        like = LikePost.objects.filter(user=request.user, post=post)

        if not like.exists():
            return Response({'error': 'You don\'t like this post'}, status=status.HTTP_400_BAD_REQUEST)

        like.delete()

        # Delete like notification
        from notifications.utils import delete_related_notifications
        delete_related_notifications(
            notification_type='like_post',
            sender=request.user,
            recipient=post.created_by,
            related_post=post
        )

        return Response({'message': 'Post unliked successfully'}, status=status.HTTP_200_OK)
    except Post.DoesNotExist:
        return Response({'error': 'Post not found'}, status=status.HTTP_404_NOT_FOUND)


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def user_posts(request, user_id):
    posts = get_visible_posts(request.user).filter(created_by_id=user_id)

    # Pagination
    paginator = PageNumberPagination()
    paginator.page_size = 20
    result_page = paginator.paginate_queryset(posts, request)

    serializer = PostSerializer(result_page, many=True, context={'request': request})
    return paginator.get_paginated_response(serializer.data)


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def category_posts(request, category_id):
    posts = get_visible_posts(request.user).filter(category_id=category_id)

    # Pagination
    paginator = PageNumberPagination()
    paginator.page_size = 20
    result_page = paginator.paginate_queryset(posts, request)

    serializer = PostSerializer(result_page, many=True, context={'request': request})
    return paginator.get_paginated_response(serializer.data)


# Nouvelles fonctions

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def recommended_posts(request):
    """
    Retourne les posts recommandés pour l'utilisateur connecté :
    - Posts des utilisateurs suivis
    - Posts des catégories suivies
    - Triés par date de création (plus récents d'abord)
    """
    from follows.models import FollowUser, FollowCategory

    # Récupérer les utilisateurs suivis
    followed_users = FollowUser.objects.filter(
        follower=request.user
    ).values_list('followed_id', flat=True)

    # Récupérer les catégories suivies
    followed_categories = FollowCategory.objects.filter(
        user=request.user
    ).values_list('category_id', flat=True)

    # Construire la requête avec visibilité
    posts = get_visible_posts(request.user)

    # Filtrer par utilisateurs suivis ou catégories suivies
    if followed_users or followed_categories:
        posts = posts.filter(
            Q(created_by_id__in=followed_users) |
            Q(category_id__in=followed_categories)
        )

    # Trier par date de création (plus récents d'abord)
    posts = posts.order_by('-created_at')

    # Pagination
    paginator = PageNumberPagination()
    paginator.page_size = 20
    result_page = paginator.paginate_queryset(posts, request)

    serializer = RecommendedPostSerializer(result_page, many=True, context={'request': request})
    return paginator.get_paginated_response(serializer.data)


@api_view(['GET'])
@permission_classes([AllowAny])
def recent_posts(request):
    """
    Retourne les posts les plus récents visibles pour l'utilisateur
    """
    posts = get_visible_posts(request.user).order_by('-created_at')

    # Pagination
    paginator = PageNumberPagination()
    paginator.page_size = 20
    result_page = paginator.paginate_queryset(posts, request)

    serializer = RecommendedPostSerializer(result_page, many=True, context={'request': request})
    return paginator.get_paginated_response(serializer.data)


@api_view(['GET'])
@permission_classes([AllowAny])
def similar_posts(request, post_id):
    """
    Retourne des posts similaires basés sur un post donné :
    - Si connecté : similaires selon les follows de l'utilisateur
    - Si non connecté : similaires selon la catégorie du post
    """
    try:
        base_post = get_visible_posts(request.user).get(id=post_id)
    except Post.DoesNotExist:
        return Response({'error': 'Post not found'}, status=status.HTTP_404_NOT_FOUND)

    if request.user.is_authenticated:
        # Utilisateur connecté : basé sur ses follows
        from follows.models import FollowUser, FollowCategory

        followed_users = FollowUser.objects.filter(
            follower=request.user
        ).values_list('followed_id', flat=True)

        followed_categories = FollowCategory.objects.filter(
            user=request.user
        ).values_list('category_id', flat=True)

        # Posts similaires : même catégorie ou même auteur, dans les follows
        similar_posts = get_visible_posts(request.user).exclude(id=post_id).filter(
            Q(
                Q(category_id=base_post.category_id) |
                Q(created_by_id=base_post.created_by_id)
            ) &
            Q(
                Q(created_by_id__in=followed_users) |
                Q(category_id__in=followed_categories)
            )
        )
    else:
        # Utilisateur non connecté : basé sur la catégorie du post
        if base_post.category:
            similar_posts = get_visible_posts(request.user).filter(
                category_id=base_post.category_id
            ).exclude(id=post_id)
        else:
            similar_posts = get_visible_posts(request.user).exclude(id=post_id).order_by('-created_at')

    # Trier par pertinence (d'abord par même catégorie, puis par date)
    similar_posts = similar_posts.order_by('-created_at')

    # Pagination
    paginator = PageNumberPagination()
    paginator.page_size = 10
    result_page = paginator.paginate_queryset(similar_posts, request)

    serializer = RecommendedPostSerializer(result_page, many=True, context={'request': request})
    return paginator.get_paginated_response(serializer.data)


@api_view(['GET'])
@permission_classes([AllowAny])
def search_posts(request):
    """
    Recherche des posts par mots-clés dans le contenu ou le nom de la catégorie
    Paramètre GET: q (query)
    """
    query = request.GET.get('q', '').strip()

    if not query:
        return Response({'error': 'The search parameter "q" is required'},
                       status=status.HTTP_400_BAD_REQUEST)

    # Utiliser une seule requête avec Q objects
    from django.db.models import Q
    from categories.models import Category

    # Rechercher les posts qui correspondent soit au contenu, soit à la catégorie
    all_posts = get_visible_posts(request.user).filter(
        Q(content__icontains=query) |
        Q(category__title__icontains=query)
    ).distinct().order_by('-created_at')

    # Pagination
    paginator = PageNumberPagination()
    paginator.page_size = 20
    result_page = paginator.paginate_queryset(all_posts, request)

    serializer = RecommendedPostSerializer(result_page, many=True, context={'request': request})
    return paginator.get_paginated_response(serializer.data)


@api_view(['GET'])
@permission_classes([AllowAny])
def feed_posts(request):
    """
    Vue unifiée pour le feed :
    - Si connecté : posts recommandés selon les follows
    - Si non connecté : posts les plus récents
    """
    if request.user.is_authenticated:
        # Utiliser la logique des posts recommandés
        from follows.models import FollowUser, FollowCategory

        followed_users = FollowUser.objects.filter(
            follower=request.user
        ).values_list('followed_id', flat=True)

        followed_categories = FollowCategory.objects.filter(
            user=request.user
        ).values_list('category_id', flat=True)

        posts = get_visible_posts(request.user)

        # Strict filtering: Only show posts from self, followed users, or categories
        posts = posts.filter(
            Q(created_by=request.user) |
            Q(created_by_id__in=followed_users) |
            Q(category_id__in=followed_categories)
        )

        posts = posts.order_by('-created_at')
    else:
        # Posts les plus récents (déjà filtrés par get_visible_posts pour les anonymes)
        posts = get_visible_posts(request.user).order_by('-created_at')

    # Pagination
    paginator = PageNumberPagination()
    paginator.page_size = 20
    result_page = paginator.paginate_queryset(posts, request)

    serializer = RecommendedPostSerializer(result_page, many=True, context={'request': request})
    return paginator.get_paginated_response(serializer.data)


@api_view(['GET'])
@permission_classes([AllowAny])
def trending_posts(request):
    """
    Retourne les posts tendances basés sur le nombre de likes et de commentaires.
    Pour les utilisateurs connectés, filtre selon la visibilité.
    """
    from django.db.models import Count, F

    # Base query based on visibility
    if request.user.is_authenticated:
        # Allow Public posts OR Close Friends posts
        posts = get_visible_posts(request.user).filter(
            Q(audience='PUBLIC', created_by__is_private=False) |
            Q(audience='CLOSE_FRIENDS')
        )
    else:
        # For anonymous users, get_visible_posts handles public/active filter
        posts = get_visible_posts(None)

    # Annotate with interaction counts
    posts = posts.annotate(
        likes_count=Count('likepost', distinct=True),
        comments_count=Count('comments', distinct=True)
    ).annotate(
        total_interactions=F('likes_count') + F('comments_count')
    ).order_by('-total_interactions', '-created_at')

    # Pagination
    paginator = PageNumberPagination()
    paginator.page_size = 20
    result_page = paginator.paginate_queryset(posts, request)

    serializer = RecommendedPostSerializer(result_page, many=True, context={'request': request})
    return paginator.get_paginated_response(serializer.data)


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def explore_feed(request):
    """
    Feed de découverte pour l'utilisateur connecté.
    Montre du contenu populaire de comptes NON suivis.
    """
    from django.db.models import Count, F
    from follows.models import FollowUser

    # Get IDs of users currently followed
    followed_user_ids = FollowUser.objects.filter(follower=request.user).values_list('followed_id', flat=True)

    # Base query: Visible posts that are:
    # 1. Public AND from non-private NON-followed users
    # 2. OR Close Friends posts (regardless of follow status)
    # get_visible_posts handles blocked/restricted users automatically
    posts = get_visible_posts(request.user).filter(
        (Q(audience='PUBLIC', created_by__is_private=False) & ~Q(created_by_id__in=followed_user_ids)) |
        Q(audience='CLOSE_FRIENDS')
    ).exclude(
    ).exclude(
        created_by=request.user
    )

    # Annotate and sort by "hotness"
    posts = posts.annotate(
        likes_count=Count('likepost', distinct=True),
        comments_count=Count('comments', distinct=True)
    ).annotate(
        total_interactions=F('likes_count') + F('comments_count')
    ).order_by('-total_interactions', '-created_at')

    # Pagination
    paginator = PageNumberPagination()
    paginator.page_size = 20
    result_page = paginator.paginate_queryset(posts, request)

    serializer = RecommendedPostSerializer(result_page, many=True, context={'request': request})
    return paginator.get_paginated_response(serializer.data)
