from django.contrib.auth import get_user_model
from django.db.models import Q
from django.shortcuts import get_object_or_404
from django.utils import timezone
from rest_framework import status, viewsets
from rest_framework.decorators import action, api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from .models import BlogPost, Bug, BugStatus, Friendship, FriendshipStatus, Message
from .serializers import (
    BlogPostSerializer,
    BugSerializer,
    FriendRequestSerializer,
    FriendshipSerializer,
    MessageCreateSerializer,
    MessageDetailSerializer,
    MessageListSerializer,
)

User = get_user_model()


# ── Member search (for adding friends) ───────────────────────────────────────

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def member_search(request):
    q = request.query_params.get('q', '').strip()
    if len(q) < 2:
        return Response([])
    users = (
        User.objects
        .exclude(pk=request.user.pk)
        .filter(
            Q(username__icontains=q) |
            Q(first_name__icontains=q) |
            Q(last_name__icontains=q)
        )[:20]
    )
    data = [
        {
            'id': u.id,
            'username': u.username,
            'display_name': (f'{u.first_name} {u.last_name}'.strip()) or u.username,
        }
        for u in users
    ]
    return Response(data)


# ── Messages ──────────────────────────────────────────────────────────────────

class MessageViewSet(viewsets.GenericViewSet):
    permission_classes = [IsAuthenticated]

    def list(self, request):
        """Inbox: messages received by the current user."""
        qs = (
            Message.objects
            .filter(recipient=request.user, deleted_by_recipient=False)
            .select_related('sender', 'recipient')
            .order_by('-sent_at')
        )
        return Response(MessageListSerializer(qs, many=True).data)

    def create(self, request):
        ser = MessageCreateSerializer(data=request.data, context={'request': request})
        ser.is_valid(raise_exception=True)
        msg = ser.save(sender=request.user)
        return Response(MessageDetailSerializer(msg).data, status=status.HTTP_201_CREATED)

    def retrieve(self, request, pk=None):
        user = request.user
        msg = get_object_or_404(
            Message,
            Q(sender=user, deleted_by_sender=False) |
            Q(recipient=user, deleted_by_recipient=False),
            pk=pk,
        )
        if msg.recipient == user and msg.read_at is None:
            msg.read_at = timezone.now()
            msg.save(update_fields=['read_at'])
        return Response(MessageDetailSerializer(msg).data)

    def destroy(self, request, pk=None):
        user = request.user
        msg = get_object_or_404(
            Message,
            Q(sender=user) | Q(recipient=user),
            pk=pk,
        )
        if msg.sender == user:
            msg.deleted_by_sender = True
        if msg.recipient == user:
            msg.deleted_by_recipient = True
        msg.save(update_fields=['deleted_by_sender', 'deleted_by_recipient'])
        return Response(status=status.HTTP_204_NO_CONTENT)

    @action(detail=False, methods=['get'], url_path='sent')
    def sent(self, request):
        qs = (
            Message.objects
            .filter(sender=request.user, deleted_by_sender=False)
            .select_related('sender', 'recipient')
            .order_by('-sent_at')
        )
        return Response(MessageListSerializer(qs, many=True).data)

    @action(detail=False, methods=['get'], url_path='unread-count')
    def unread_count(self, request):
        count = Message.objects.filter(
            recipient=request.user, read_at__isnull=True, deleted_by_recipient=False
        ).count()
        return Response({'unread': count})


# ── BlogPost ──────────────────────────────────────────────────────────────────

class BlogPostViewSet(viewsets.ModelViewSet):
    permission_classes = [IsAuthenticated]
    serializer_class   = BlogPostSerializer
    search_fields      = ['title', 'body']
    ordering_fields    = ['created_at']

    def get_queryset(self):
        user = self.request.user
        return (
            BlogPost.objects
            .filter(Q(author=user) | Q(is_public=True))
            .select_related('author')
        )

    def perform_create(self, serializer):
        serializer.save(author=self.request.user)

    def check_write_permission(self, instance):
        from rest_framework.exceptions import PermissionDenied
        if instance.author != self.request.user and not self.request.user.is_staff:
            raise PermissionDenied

    def perform_update(self, serializer):
        self.check_write_permission(self.get_object())
        serializer.save()

    def perform_destroy(self, instance):
        self.check_write_permission(instance)
        instance.delete()


# ── Bug ───────────────────────────────────────────────────────────────────────

class BugViewSet(viewsets.ModelViewSet):
    permission_classes = [IsAuthenticated]
    serializer_class   = BugSerializer
    filterset_fields   = ['severity', 'status']
    search_fields      = ['title', 'description']
    ordering_fields    = ['created_at', 'severity']

    def get_queryset(self):
        user = self.request.user
        if user.is_staff:
            return Bug.objects.select_related('reporter').all()
        return Bug.objects.filter(reporter=user).select_related('reporter')

    def perform_create(self, serializer):
        serializer.save(reporter=self.request.user)

    @action(detail=True, methods=['post'], url_path='resolve')
    def resolve(self, request, pk=None):
        from rest_framework.exceptions import PermissionDenied
        if not request.user.is_staff:
            raise PermissionDenied
        bug = self.get_object()
        bug.status = BugStatus.RESOLVED
        bug.resolved_at = timezone.now()
        bug.save(update_fields=['status', 'resolved_at', 'updated_at'])
        return Response(BugSerializer(bug).data)


# ── Friendship ────────────────────────────────────────────────────────────────

class FriendshipViewSet(viewsets.GenericViewSet):
    permission_classes = [IsAuthenticated]
    serializer_class   = FriendshipSerializer

    def list(self, request):
        """Accepted friends."""
        user = request.user
        qs = (
            Friendship.objects
            .filter(Q(from_user=user) | Q(to_user=user), status=FriendshipStatus.ACCEPTED)
            .select_related('from_user', 'to_user')
        )
        return Response(FriendshipSerializer(qs, many=True).data)

    def create(self, request):
        ser = FriendRequestSerializer(data=request.data, context={'request': request})
        ser.is_valid(raise_exception=True)
        to_user = ser.validated_data['to_user']
        user = request.user

        existing = Friendship.objects.filter(
            Q(from_user=user, to_user=to_user) |
            Q(from_user=to_user, to_user=user)
        ).first()
        if existing:
            return Response({'detail': 'A friendship or request already exists.'}, status=status.HTTP_409_CONFLICT)

        friendship = Friendship.objects.create(from_user=user, to_user=to_user)
        return Response(FriendshipSerializer(friendship).data, status=status.HTTP_201_CREATED)

    def destroy(self, request, pk=None):
        user = request.user
        friendship = get_object_or_404(
            Friendship,
            Q(from_user=user) | Q(to_user=user),
            pk=pk,
        )
        friendship.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

    @action(detail=False, methods=['get'], url_path='requests')
    def requests(self, request):
        """Incoming pending requests."""
        qs = (
            Friendship.objects
            .filter(to_user=request.user, status=FriendshipStatus.PENDING)
            .select_related('from_user', 'to_user')
        )
        return Response(FriendshipSerializer(qs, many=True).data)

    @action(detail=False, methods=['get'], url_path='sent-requests')
    def sent_requests(self, request):
        """Outgoing pending requests."""
        qs = (
            Friendship.objects
            .filter(from_user=request.user, status=FriendshipStatus.PENDING)
            .select_related('from_user', 'to_user')
        )
        return Response(FriendshipSerializer(qs, many=True).data)

    @action(detail=True, methods=['post'], url_path='accept')
    def accept(self, request, pk=None):
        friendship = get_object_or_404(
            Friendship, pk=pk, to_user=request.user, status=FriendshipStatus.PENDING
        )
        friendship.status = FriendshipStatus.ACCEPTED
        friendship.save(update_fields=['status', 'updated_at'])
        return Response(FriendshipSerializer(friendship).data)

    @action(detail=True, methods=['post'], url_path='decline')
    def decline(self, request, pk=None):
        """Decline an incoming request or cancel an outgoing one."""
        user = request.user
        friendship = get_object_or_404(
            Friendship,
            Q(from_user=user) | Q(to_user=user),
            pk=pk, status=FriendshipStatus.PENDING,
        )
        friendship.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)
