"""Consultation API: doctors, book, list, message, video-call, doctor inbox."""
import random
import string
from django.utils import timezone
from rest_framework.views import APIView

from core.models import AppUser, Consultation, Notification
from .auth_utils import ok, err
from .permissions import IsAppUser, IsDoctorOrAdmin
from .serializers import ConsultationSerializer, UserPublicSerializer


class DoctorsListView(APIView):
    permission_classes = [IsAppUser]

    def get(self, request):
        doctors = AppUser.objects.filter(role='doctor', status='active')
        return ok(UserPublicSerializer(doctors, many=True).data)


class BookConsultationView(APIView):
    permission_classes = [IsAppUser]

    def post(self, request):
        d = request.data
        doctor_id = d.get('doctorId') or d.get('doctor_id')
        if not doctor_id:
            return err('doctorId is required.', 400)
        try:
            doctor = AppUser.objects.get(id=doctor_id, role='doctor', status='active')
        except AppUser.DoesNotExist:
            return err('Doctor not found.', 404)

        consultation = Consultation.objects.create(
            user=request.app_user,
            doctor=doctor,
            topic=d.get('topic', ''),
            appointment_time=d.get('appointmentTime') or d.get('appointment_time'),
            status='pending',
            chat_history=[],
            created_at=timezone.now(),
            updated_at=timezone.now(),
        )
        # Notify doctor
        Notification.objects.create(
            user=doctor,
            title='New Consultation Request',
            message=f'{request.app_user.name} requested a consultation.',
            type='appointment',
            is_read=False,
            created_at=timezone.now(),
        )
        return ok(ConsultationSerializer(consultation).data,
                  'Consultation booked.', 201)


class ConsultationListView(APIView):
    permission_classes = [IsAppUser]

    def get(self, request):
        user = request.app_user
        if user.role == 'doctor':
            qs = Consultation.objects.filter(doctor=user)
        else:
            qs = Consultation.objects.filter(user=user)
        return ok(ConsultationSerializer(qs, many=True).data)


class SendMessageView(APIView):
    permission_classes = [IsAppUser]

    def post(self, request):
        d = request.data
        consultation_id = d.get('consultationId') or d.get('consultation_id')
        message_text = d.get('message', '')
        if not consultation_id:
            return err('consultationId is required.', 400)

        user = request.app_user
        try:
            if user.role == 'doctor':
                c = Consultation.objects.get(id=consultation_id, doctor=user)
            else:
                c = Consultation.objects.get(id=consultation_id, user=user)
        except Consultation.DoesNotExist:
            return err('Consultation not found.', 404)

        history = c.chat_history or []
        msg = {
            'sender_id': user.id,
            'sender_name': user.name,
            'sender_role': user.role,
            'message': message_text,
            'timestamp': timezone.now().isoformat(),
        }
        history.append(msg)
        Consultation.objects.filter(id=c.id).update(
            chat_history=history, updated_at=timezone.now(),
        )

        # Notify the other party
        recipient = c.user if user.role == 'doctor' else c.doctor
        Notification.objects.create(
            user=recipient,
            title='New Message',
            message=f'{user.name}: {message_text[:80]}',
            type='appointment',
            is_read=False,
            created_at=timezone.now(),
        )
        return ok(msg, 'Message sent.')


class VideoCallView(APIView):
    permission_classes = [IsAppUser]

    def post(self, request, consultation_id):
        user = request.app_user
        try:
            if user.role == 'doctor':
                c = Consultation.objects.get(id=consultation_id, doctor=user)
            else:
                c = Consultation.objects.get(id=consultation_id, user=user)
        except Consultation.DoesNotExist:
            return err('Consultation not found.', 404)

        room_code = f'narinest-{c.id}-{"".join(random.choices(string.ascii_lowercase + string.digits, k=8))}'
        meeting_url = f'https://meet.jit.si/{room_code}'
        return ok({'meetingUrl': meeting_url, 'roomCode': room_code})


class DoctorInboxView(APIView):
    """Doctor-only: list all consultations grouped by patient."""
    permission_classes = [IsDoctorOrAdmin]

    def get(self, request):
        consultations = Consultation.objects.filter(
            doctor=request.app_user,
        ).select_related('user').order_by('-updated_at')
        return ok(ConsultationSerializer(consultations, many=True).data)


class ConsultationMessagesView(APIView):
    """Get or post messages within a specific consultation."""
    permission_classes = [IsAppUser]

    def get(self, request, consultation_id):
        user = request.app_user
        try:
            if user.role == 'doctor':
                c = Consultation.objects.get(id=consultation_id, doctor=user)
            else:
                c = Consultation.objects.get(id=consultation_id, user=user)
        except Consultation.DoesNotExist:
            return err('Consultation not found.', 404)
        return ok(c.chat_history or [])

    def post(self, request, consultation_id):
        return SendMessageView().post(
            _RequestWithConsultationId(request, consultation_id),
        )


class _RequestWithConsultationId:
    """Thin wrapper to inject consultation_id into request.data."""
    def __init__(self, request, cid):
        self._r = request
        self.data = {**request.data, 'consultationId': cid}
        self.app_user = request.app_user
        self.META = request.META
