from rest_framework import status
from rest_framework.decorators import api_view, permission_classes, parser_classes
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework.response import Response
from django.core.cache import cache as redis_cache
from django.utils import timezone
from django.conf import settings

from .models import (
    LiveSession, LiveProductPin, LiveComment,
    LiveReaction, LiveView, LiveAnalyticsEvent,
)
from .serializers import (
    LiveSessionListSerializer, LiveSessionDetailSerializer,
    LiveSessionCreateSerializer, LiveProductPinSerializer,
    LiveCommentSerializer, LiveSummarySerializer,
)
from .agora_utils import generate_agora_token
from accounts.models import Follow


# ---------- public lists ----------

@api_view(['GET'])
@permission_classes([AllowAny])
def list_live_now(request):
    """Active live sessions, cached 10s"""
    cached = redis_cache.get('live_now_sessions')
    if cached is None:
        sessions = LiveSession.objects.filter(
            status='live', is_active=True
        ).select_related('vendor', 'vendor__vendor_profile').order_by('-started_at')
        serializer = LiveSessionListSerializer(sessions, many=True, context={'request': request})
        cached = serializer.data
        redis_cache.set('live_now_sessions', cached, 10)
    return Response(cached)


@api_view(['GET'])
@permission_classes([AllowAny])
def list_upcoming(request):
    """Scheduled sessions in the future"""
    sessions = LiveSession.objects.filter(
        status='scheduled', is_active=True,
        scheduled_at__gt=timezone.now(),
    ).select_related('vendor', 'vendor__vendor_profile').order_by('scheduled_at')
    serializer = LiveSessionListSerializer(sessions, many=True, context={'request': request})
    return Response(serializer.data)


@api_view(['GET'])
@permission_classes([AllowAny])
def list_replays(request):
    """Ended sessions with replay video, paginated 20/page"""
    page = int(request.query_params.get('page', 1))
    per_page = 20
    offset = (page - 1) * per_page

    sessions = LiveSession.objects.filter(
        status='ended', is_active=True
    ).exclude(replay_video='').exclude(replay_video__isnull=True).select_related(
        'vendor', 'vendor__vendor_profile'
    ).order_by('-ended_at')

    total = sessions.count()
    sessions_page = sessions[offset:offset + per_page]
    serializer = LiveSessionListSerializer(sessions_page, many=True, context={'request': request})

    return Response({
        'results': serializer.data,
        'total': total,
        'page': page,
        'has_more': offset + per_page < total,
    })


@api_view(['GET'])
@permission_classes([AllowAny])
def get_live_session(request, slug):
    """Detail by slug, increment total_views"""
    try:
        session = LiveSession.objects.select_related(
            'vendor', 'vendor__vendor_profile'
        ).prefetch_related('product_pins__product').get(slug=slug, is_active=True)
    except LiveSession.DoesNotExist:
        return Response({'error': 'Live session not found'}, status=status.HTTP_404_NOT_FOUND)

    session.total_views += 1
    session.save(update_fields=['total_views'])

    serializer = LiveSessionDetailSerializer(session, context={'request': request})
    return Response(serializer.data)


# ---------- vendor CRUD ----------

@api_view(['POST'])
@permission_classes([IsAuthenticated])
@parser_classes([MultiPartParser, FormParser])
def create_live_session(request):
    """Create a live session. If no scheduled_at, go live immediately."""
    if request.user.user_type != 'vendor':
        return Response({'error': 'Only vendors can go live'}, status=status.HTTP_403_FORBIDDEN)

    try:
        profile = request.user.vendor_profile
        if not profile.is_upgraded:
            return Response(
                {'error': 'Upgrade to Pro to go live'},
                status=status.HTTP_403_FORBIDDEN,
            )
    except Exception:
        return Response({'error': 'Vendor profile not found'}, status=status.HTTP_400_BAD_REQUEST)

    serializer = LiveSessionCreateSerializer(data=request.data)
    if serializer.is_valid():
        session = serializer.save(vendor=request.user)

        # If no scheduled_at, go live immediately
        if not session.scheduled_at:
            session.status = 'live'
            session.started_at = timezone.now()
            session.save(update_fields=['status', 'started_at'])

            if session.notify_followers:
                _notify_followers_live_started(session)
        else:
            if session.notify_followers:
                _notify_followers_live_scheduled(session)

        redis_cache.delete('live_now_sessions')
        return Response(
            LiveSessionDetailSerializer(session, context={'request': request}).data,
            status=status.HTTP_201_CREATED,
        )
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def go_live(request, session_id):
    """Transition scheduled -> live"""
    try:
        session = LiveSession.objects.get(id=session_id, vendor=request.user)
    except LiveSession.DoesNotExist:
        return Response({'error': 'Session not found'}, status=status.HTTP_404_NOT_FOUND)

    if session.status != 'scheduled':
        return Response({'error': 'Session is not in scheduled state'}, status=status.HTTP_400_BAD_REQUEST)

    session.status = 'live'
    session.started_at = timezone.now()
    session.save(update_fields=['status', 'started_at'])

    if session.notify_followers:
        _notify_followers_live_started(session)

    redis_cache.delete('live_now_sessions')
    serializer = LiveSessionDetailSerializer(session, context={'request': request})
    return Response(serializer.data)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def end_live(request, session_id):
    """End a live session, return summary"""
    try:
        session = LiveSession.objects.get(id=session_id, vendor=request.user)
    except LiveSession.DoesNotExist:
        return Response({'error': 'Session not found'}, status=status.HTTP_404_NOT_FOUND)

    if session.status != 'live':
        return Response({'error': 'Session is not live'}, status=status.HTTP_400_BAD_REQUEST)

    session.status = 'ended'
    session.ended_at = timezone.now()
    session.save(update_fields=['status', 'ended_at'])

    redis_cache.delete('live_now_sessions')
    serializer = LiveSummarySerializer(session)
    return Response(serializer.data)


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def get_live_summary(request, session_id):
    """Post-live stats (vendor only)"""
    try:
        session = LiveSession.objects.get(id=session_id, vendor=request.user)
    except LiveSession.DoesNotExist:
        return Response({'error': 'Session not found'}, status=status.HTTP_404_NOT_FOUND)

    serializer = LiveSummarySerializer(session)
    return Response(serializer.data)


# ---------- products ----------

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def pin_product(request, session_id):
    """Un-pin all, pin specified product"""
    try:
        session = LiveSession.objects.get(id=session_id, vendor=request.user)
    except LiveSession.DoesNotExist:
        return Response({'error': 'Session not found'}, status=status.HTTP_404_NOT_FOUND)

    product_id = request.data.get('product_id')
    if not product_id:
        return Response({'error': 'product_id required'}, status=status.HTTP_400_BAD_REQUEST)

    # Un-pin all
    session.product_pins.update(is_currently_pinned=False)

    # Pin the specified one
    try:
        pin = session.product_pins.get(product_id=product_id)
        pin.is_currently_pinned = True
        pin.pinned_at = timezone.now()
        pin.save(update_fields=['is_currently_pinned', 'pinned_at'])
    except LiveProductPin.DoesNotExist:
        return Response({'error': 'Product not in session'}, status=status.HTTP_404_NOT_FOUND)

    serializer = LiveProductPinSerializer(pin, context={'request': request})
    return Response(serializer.data)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def unpin_product(request, session_id):
    """Un-pin all products"""
    try:
        session = LiveSession.objects.get(id=session_id, vendor=request.user)
    except LiveSession.DoesNotExist:
        return Response({'error': 'Session not found'}, status=status.HTTP_404_NOT_FOUND)

    session.product_pins.update(is_currently_pinned=False)
    return Response({'status': 'ok'})


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def add_products(request, session_id):
    """Add products to session"""
    try:
        session = LiveSession.objects.get(id=session_id, vendor=request.user)
    except LiveSession.DoesNotExist:
        return Response({'error': 'Session not found'}, status=status.HTTP_404_NOT_FOUND)

    product_ids = request.data.get('product_ids', [])
    if not product_ids:
        return Response({'error': 'product_ids required'}, status=status.HTTP_400_BAD_REQUEST)

    existing = set(session.product_pins.values_list('product_id', flat=True))
    max_order = session.product_pins.count()

    created = []
    for pid in product_ids:
        if pid not in existing:
            pin = LiveProductPin.objects.create(
                session=session,
                product_id=pid,
                order=max_order,
            )
            created.append(pin)
            max_order += 1

    serializer = LiveProductPinSerializer(created, many=True, context={'request': request})
    return Response(serializer.data, status=status.HTTP_201_CREATED)


@api_view(['DELETE'])
@permission_classes([IsAuthenticated])
def remove_product(request, session_id, product_id):
    """Remove product from session"""
    try:
        session = LiveSession.objects.get(id=session_id, vendor=request.user)
    except LiveSession.DoesNotExist:
        return Response({'error': 'Session not found'}, status=status.HTTP_404_NOT_FOUND)

    deleted, _ = session.product_pins.filter(product_id=product_id).delete()
    if deleted == 0:
        return Response({'error': 'Product not in session'}, status=status.HTTP_404_NOT_FOUND)

    return Response(status=status.HTTP_204_NO_CONTENT)


# ---------- chat / reactions ----------

@api_view(['GET'])
@permission_classes([AllowAny])
def get_comments(request, session_id):
    """Get comments, supports ?since_id=X for polling, returns newest 50"""
    try:
        session = LiveSession.objects.get(id=session_id, is_active=True)
    except LiveSession.DoesNotExist:
        return Response({'error': 'Session not found'}, status=status.HTTP_404_NOT_FOUND)

    since_id = request.query_params.get('since_id')
    comments = session.comments.select_related('user')
    if since_id:
        comments = comments.filter(id__gt=int(since_id))

    comments = comments.order_by('-created_at')[:50]
    serializer = LiveCommentSerializer(
        reversed(list(comments)), many=True, context={'request': request}
    )
    return Response(serializer.data)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def post_comment(request, session_id):
    """Create comment, increment count"""
    try:
        session = LiveSession.objects.get(id=session_id, is_active=True)
    except LiveSession.DoesNotExist:
        return Response({'error': 'Session not found'}, status=status.HTTP_404_NOT_FOUND)

    content = request.data.get('content', '').strip()
    if not content:
        return Response({'error': 'Content required'}, status=status.HTTP_400_BAD_REQUEST)
    if len(content) > 500:
        return Response({'error': 'Content too long (max 500)'}, status=status.HTTP_400_BAD_REQUEST)

    comment = LiveComment.objects.create(
        session=session,
        user=request.user,
        content=content,
    )
    session.comments_count += 1
    session.save(update_fields=['comments_count'])

    serializer = LiveCommentSerializer(comment, context={'request': request})
    return Response(serializer.data, status=status.HTTP_201_CREATED)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def post_reaction(request, session_id):
    """Create reaction, increment count"""
    try:
        session = LiveSession.objects.get(id=session_id, is_active=True)
    except LiveSession.DoesNotExist:
        return Response({'error': 'Session not found'}, status=status.HTTP_404_NOT_FOUND)

    reaction_type = request.data.get('reaction_type', '')
    valid_types = ['fire', 'heart', 'heart_eyes']
    if reaction_type not in valid_types:
        return Response(
            {'error': f'Invalid reaction type. Must be one of: {", ".join(valid_types)}'},
            status=status.HTTP_400_BAD_REQUEST,
        )

    LiveReaction.objects.create(
        session=session,
        user=request.user,
        reaction_type=reaction_type,
    )
    session.reactions_count += 1
    session.save(update_fields=['reactions_count'])

    return Response({'status': 'ok', 'reaction_type': reaction_type})


# ---------- viewer tracking ----------

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def join_live(request, session_id):
    """Create LiveView, increment viewer_count, update peak"""
    try:
        session = LiveSession.objects.get(id=session_id, is_active=True)
    except LiveSession.DoesNotExist:
        return Response({'error': 'Session not found'}, status=status.HTTP_404_NOT_FOUND)

    is_replay = session.status == 'ended'
    LiveView.objects.create(
        session=session,
        viewer=request.user,
        is_replay_view=is_replay,
    )

    if is_replay:
        session.replay_views += 1
        session.save(update_fields=['replay_views'])
    else:
        session.viewer_count += 1
        if session.viewer_count > session.peak_viewers:
            session.peak_viewers = session.viewer_count
        session.save(update_fields=['viewer_count', 'peak_viewers'])

    return Response({
        'status': 'ok',
        'viewer_count': session.viewer_count,
    })


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def leave_live(request, session_id):
    """Set left_at, decrement viewer_count"""
    try:
        session = LiveSession.objects.get(id=session_id, is_active=True)
    except LiveSession.DoesNotExist:
        return Response({'error': 'Session not found'}, status=status.HTTP_404_NOT_FOUND)

    view = LiveView.objects.filter(
        session=session, viewer=request.user, left_at__isnull=True
    ).order_by('-joined_at').first()

    if view:
        view.left_at = timezone.now()
        view.save(update_fields=['left_at'])

    if session.status == 'live' and session.viewer_count > 0:
        session.viewer_count -= 1
        session.save(update_fields=['viewer_count'])

    return Response({'status': 'ok', 'viewer_count': session.viewer_count})


# ---------- analytics ----------

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def track_event(request, session_id):
    """Track whatsapp_click, call_click, product_view, share"""
    try:
        session = LiveSession.objects.get(id=session_id, is_active=True)
    except LiveSession.DoesNotExist:
        return Response({'error': 'Session not found'}, status=status.HTTP_404_NOT_FOUND)

    event_type = request.data.get('event_type', '')
    valid_types = ['whatsapp_click', 'call_click', 'product_view', 'share']
    if event_type not in valid_types:
        return Response({'error': 'Invalid event type'}, status=status.HTTP_400_BAD_REQUEST)

    product_id = request.data.get('product_id')

    LiveAnalyticsEvent.objects.create(
        session=session,
        user=request.user,
        event_type=event_type,
        product_id=product_id,
    )

    # Update denormalized counters
    if event_type == 'whatsapp_click':
        session.whatsapp_clicks += 1
        session.save(update_fields=['whatsapp_clicks'])
    elif event_type == 'call_click':
        session.call_clicks += 1
        session.save(update_fields=['call_clicks'])
    elif event_type == 'product_view':
        session.product_views_count += 1
        session.save(update_fields=['product_views_count'])
    elif event_type == 'share':
        session.shares_count += 1
        session.save(update_fields=['shares_count'])

    return Response({'status': 'ok'})


# ---------- agora token ----------

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def get_agora_token(request, session_id):
    """Generate token (publisher for vendor, subscriber for viewer)"""
    try:
        session = LiveSession.objects.get(id=session_id, is_active=True)
    except LiveSession.DoesNotExist:
        return Response({'error': 'Session not found'}, status=status.HTTP_404_NOT_FOUND)

    is_publisher = request.user == session.vendor
    role = 'publisher' if is_publisher else 'subscriber'
    uid = request.user.id

    token = generate_agora_token(session.agora_channel_name, uid, role)

    return Response({
        'token': token,
        'channel_name': session.agora_channel_name,
        'uid': uid,
        'role': role,
        'app_id': getattr(settings, 'AGORA_APP_ID', ''),
    })


# ---------- vendor lists ----------

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def vendor_live_sessions(request):
    """Vendor's own sessions"""
    if request.user.user_type != 'vendor':
        return Response({'error': 'Vendor access required'}, status=status.HTTP_403_FORBIDDEN)

    sessions = LiveSession.objects.filter(
        vendor=request.user
    ).select_related('vendor', 'vendor__vendor_profile').order_by('-created_at')

    serializer = LiveSessionListSerializer(sessions, many=True, context={'request': request})
    return Response(serializer.data)


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def following_live_sessions(request):
    """Live/scheduled from followed vendors"""
    followed_vendor_ids = list(
        Follow.objects.filter(buyer=request.user).values_list('vendor_id', flat=True)
    )
    if not followed_vendor_ids:
        return Response([])

    sessions = LiveSession.objects.filter(
        vendor_id__in=followed_vendor_ids,
        status__in=['live', 'scheduled'],
        is_active=True,
    ).select_related('vendor', 'vendor__vendor_profile').order_by(
        '-status',  # live before scheduled
        '-started_at',
    )

    serializer = LiveSessionListSerializer(sessions, many=True, context={'request': request})
    return Response(serializer.data)


# ---------- replay upload ----------

@api_view(['POST'])
@permission_classes([IsAuthenticated])
@parser_classes([MultiPartParser, FormParser])
def upload_replay(request, session_id):
    """Upload replay video file"""
    try:
        session = LiveSession.objects.get(id=session_id, vendor=request.user)
    except LiveSession.DoesNotExist:
        return Response({'error': 'Session not found'}, status=status.HTTP_404_NOT_FOUND)

    if session.status != 'ended':
        return Response({'error': 'Session must be ended to upload replay'}, status=status.HTTP_400_BAD_REQUEST)

    replay = request.FILES.get('replay_video')
    if not replay:
        return Response({'error': 'replay_video file required'}, status=status.HTTP_400_BAD_REQUEST)

    session.replay_video = replay
    session.save(update_fields=['replay_video'])

    serializer = LiveSessionDetailSerializer(session, context={'request': request})
    return Response(serializer.data)


# ---------- helpers ----------

def _notify_followers_live_started(session):
    """Notify followers that vendor has gone live"""
    from notifications.models import Notification

    follower_ids = Follow.objects.filter(
        vendor=session.vendor
    ).values_list('buyer_id', flat=True)[:100]

    from accounts.models import User
    followers = User.objects.filter(id__in=follower_ids)

    shop_name = session.vendor.full_name
    try:
        shop_name = session.vendor.vendor_profile.shop_name
    except Exception:
        pass

    for follower in followers:
        Notification.create_notification(
            recipient=follower,
            sender=session.vendor,
            notification_type='live_started',
            title='Live Now!',
            message=f'{shop_name} is now live: {session.title}',
            link=f'/live/{session.slug}',
        )


def _notify_followers_live_scheduled(session):
    """Notify followers about scheduled live"""
    from notifications.models import Notification

    follower_ids = Follow.objects.filter(
        vendor=session.vendor
    ).values_list('buyer_id', flat=True)[:100]

    from accounts.models import User
    followers = User.objects.filter(id__in=follower_ids)

    shop_name = session.vendor.full_name
    try:
        shop_name = session.vendor.vendor_profile.shop_name
    except Exception:
        pass

    for follower in followers:
        Notification.create_notification(
            recipient=follower,
            sender=session.vendor,
            notification_type='live_scheduled',
            title='Live Scheduled',
            message=f'{shop_name} has scheduled a live: {session.title}',
            link=f'/live/{session.slug}',
        )
