"""
api/v1/web/views/chat.py

In-system network chat API. Participants are identified by distributor_code
(referral identity). Mobile/email is NEVER returned in any response.

Endpoints
---------
GET  /api/v1/web/chat/conversations/
     List all conversations for the logged-in user.

POST /api/v1/web/chat/conversations/
     Start (or get existing) conversation with a distributor_code.
     Body: { "recipient_distributor_code": "TW..." }

GET  /api/v1/web/chat/conversations/<id>/messages/
     List messages in a conversation (paginated, newest-first).

POST /api/v1/web/chat/conversations/<id>/messages/
     Send a message.
     Body: { "body": "Hello..." }

POST /api/v1/web/chat/conversations/<id>/read/
     Mark all received messages as read.
"""
import uuid
from django.db.models import Q
from rest_framework import permissions, status
from rest_framework.response import Response
from rest_framework.views import APIView

from apps.business.network_chat.models import ChatConversation, ChatMessage
from apps.business.distributor.models import DistributorID
from apps.platform.settings.models import PlatformFeatureFlag


def _display_name(user):
    full_name = f"{user.first_name or ''} {user.last_name or ''}".strip()
    if full_name:
        return full_name
    return user.username or f"User {user.id}"


def _safe_conv_dict(conv, me_user_id):
    """Serialize a ChatConversation without exposing PII."""
    is_initiator = str(conv.initiator_id) == str(me_user_id)
    my_code = conv.initiator_distributor_code if is_initiator else conv.recipient_distributor_code
    other_code = conv.recipient_distributor_code if is_initiator else conv.initiator_distributor_code
    other_user = conv.recipient if is_initiator else conv.initiator

    # Unread count for the current user
    unread = conv.messages.filter(is_read=False).exclude(sender_id=me_user_id).count()

    last_msg = conv.messages.last()
    return {
        'id': str(conv.id),
        'my_distributor_code': my_code,
        'other_distributor_code': other_code,
        'other_full_name': _display_name(other_user),
        'unread_count': unread,
        'last_message': {
            'body': last_msg.body[:120] if last_msg else None,
            'sent_at': last_msg.created_at.isoformat() if last_msg else None,
            'is_mine': str(last_msg.sender_id) == str(me_user_id) if last_msg else None,
        } if last_msg else None,
        'updated_at': conv.updated_at.isoformat(),
    }


def _safe_msg_dict(msg, me_user_id):
    return {
        'id': str(msg.id),
        'sender_code': msg.sender_distributor_code,
        'body': msg.body,
        'is_mine': str(msg.sender_id) == str(me_user_id),
        'is_read': msg.is_read,
        'created_at': msg.created_at.isoformat(),
    }


def _chat_disabled_response():
    return Response({'success': False, 'error': 'Chat is currently disabled by admin.'}, status=403)


class ConversationListView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        if not PlatformFeatureFlag.is_on(PlatformFeatureFlag.CHAT_ENABLED):
            return _chat_disabled_response()
        me = request.user
        convs = (
            ChatConversation.objects
            .filter(Q(initiator=me) | Q(recipient=me), is_active=True)
            .select_related('initiator', 'recipient')
            .prefetch_related('messages')
            .order_by('-updated_at')
        )
        return Response({
            'success': True,
            'data': [_safe_conv_dict(c, me.id) for c in convs],
        })

    def post(self, request):
        """Start or retrieve a conversation by recipient_distributor_code."""
        if not PlatformFeatureFlag.is_on(PlatformFeatureFlag.CHAT_ENABLED):
            return _chat_disabled_response()
        me = request.user
        rec_code = (request.data.get('recipient_distributor_code') or '').strip()
        my_code = (request.data.get('my_distributor_code') or '').strip()

        if not rec_code:
            return Response({'success': False, 'error': 'recipient_distributor_code is required.'}, status=400)

        # Verify recipient distributor exists
        rec_dist = DistributorID.objects.filter(distributor_code=rec_code).select_related('user').first()
        if not rec_dist:
            return Response({'success': False, 'error': 'Distributor not found.'}, status=404)

        # Must not chat with yourself
        if rec_dist.user_id == me.id:
            return Response({'success': False, 'error': 'You cannot chat with yourself.'}, status=400)

        # Resolve the initiator's distributor code
        if not my_code:
            my_dist = DistributorID.objects.filter(user=me).order_by('global_position').first()
        else:
            my_dist = DistributorID.objects.filter(distributor_code=my_code, user=me).first()

        if not my_dist:
            return Response({'success': False, 'error': 'You must have a distributor ID to start a chat.'}, status=400)

        my_code = my_dist.distributor_code

        # Get or create (check both directions)
        conv = (
            ChatConversation.objects
            .filter(
                Q(initiator_distributor_code=my_code, recipient_distributor_code=rec_code) |
                Q(initiator_distributor_code=rec_code, recipient_distributor_code=my_code)
            )
            .first()
        )
        created = False
        if not conv:
            conv = ChatConversation.objects.create(
                initiator=me,
                recipient=rec_dist.user,
                initiator_distributor_code=my_code,
                recipient_distributor_code=rec_code,
            )
            created = True

        return Response(
            {'success': True, 'data': _safe_conv_dict(conv, me.id), 'created': created},
            status=status.HTTP_201_CREATED if created else status.HTTP_200_OK,
        )


class ConversationMessageView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def _get_conv(self, request, conv_id):
        me = request.user
        try:
            conv = ChatConversation.objects.get(pk=conv_id)
        except (ChatConversation.DoesNotExist, Exception):
            return None, None
        if conv.initiator_id != me.id and conv.recipient_id != me.id:
            return None, None
        return conv, me

    def get(self, request, conv_id):
        if not PlatformFeatureFlag.is_on(PlatformFeatureFlag.CHAT_ENABLED):
            return _chat_disabled_response()
        conv, me = self._get_conv(request, conv_id)
        if not conv:
            return Response({'success': False, 'error': 'Not found.'}, status=404)

        try:
            page = max(1, int(request.query_params.get('page', 1)))
            page_size = min(100, int(request.query_params.get('page_size', 50)))
        except (TypeError, ValueError):
            page, page_size = 1, 50

        qs = conv.messages.all().order_by('created_at')
        total = qs.count()
        offset = (page - 1) * page_size
        msgs = qs[offset: offset + page_size]

        return Response({
            'success': True,
            'data': [_safe_msg_dict(m, me.id) for m in msgs],
            'pagination': {
                'total': total,
                'page': page,
                'page_size': page_size,
                'total_pages': max(1, (total + page_size - 1) // page_size),
            },
        })

    def post(self, request, conv_id):
        if not PlatformFeatureFlag.is_on(PlatformFeatureFlag.CHAT_ENABLED):
            return _chat_disabled_response()
        conv, me = self._get_conv(request, conv_id)
        if not conv:
            return Response({'success': False, 'error': 'Not found.'}, status=404)

        body = (request.data.get('body') or '').strip()
        if not body:
            return Response({'success': False, 'error': 'Message body cannot be empty.'}, status=400)
        if len(body) > 2000:
            return Response({'success': False, 'error': 'Message too long (max 2000 chars).'}, status=400)

        # Determine sender_distributor_code
        is_initiator = conv.initiator_id == me.id
        sender_code = conv.initiator_distributor_code if is_initiator else conv.recipient_distributor_code

        msg = ChatMessage.objects.create(
            conversation=conv,
            sender=me,
            sender_distributor_code=sender_code,
            body=body,
        )
        # Bump conversation updated_at
        conv.save(update_fields=['updated_at'])

        return Response(
            {'success': True, 'data': _safe_msg_dict(msg, me.id)},
            status=status.HTTP_201_CREATED,
        )


class ConversationReadView(APIView):
    """POST /chat/conversations/<id>/read/ — mark received messages as read."""
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, conv_id):
        if not PlatformFeatureFlag.is_on(PlatformFeatureFlag.CHAT_ENABLED):
            return _chat_disabled_response()
        me = request.user
        try:
            conv = ChatConversation.objects.get(pk=conv_id)
        except ChatConversation.DoesNotExist:
            return Response({'success': False, 'error': 'Not found.'}, status=404)
        if conv.initiator_id != me.id and conv.recipient_id != me.id:
            return Response({'success': False, 'error': 'Not found.'}, status=404)

        updated = conv.messages.filter(is_read=False).exclude(sender=me).update(is_read=True)
        return Response({'success': True, 'marked_read': updated})
