from rest_framework import generics, status, permissions
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework.pagination import PageNumberPagination
from django.db.models import Q, Count, Case, When, IntegerField, Exists, OuterRef, Value
from django.utils import timezone
from .models import Event, EventPackage, EventLike, EventSave
from .serializers import (
    EventSerializer, EventDetailSerializer,
    EventCreateSerializer, EventUpdateSerializer,
    EventPackageSerializer,
)
import json


class IsVendor(permissions.BasePermission):
    def has_permission(self, request, view):
        return (
            request.user.is_authenticated and
            request.user.user_type == 'vendor' and
            hasattr(request.user, 'vendor_profile')
        )


class IsAdmin(permissions.BasePermission):
    def has_permission(self, request, view):
        return (
            request.user.is_authenticated and
            request.user.user_type == 'admin'
        )


class EventPagination(PageNumberPagination):
    page_size = 20
    page_size_query_param = 'page_size'
    max_page_size = 50


# ============== PUBLIC ==============

class EventListView(generics.ListAPIView):
    """List all active events (public)"""
    serializer_class = EventSerializer
    permission_classes = [permissions.AllowAny]
    pagination_class = EventPagination

    def get_queryset(self):
        queryset = Event.objects.filter(status='active').select_related('vendor', 'vendor__user').prefetch_related('packages')

        # Filter by vendor ID
        vendor = self.request.query_params.get('vendor')
        if vendor:
            queryset = queryset.filter(vendor_id=vendor)

        # Filter by vendor slug
        vendor_slug = self.request.query_params.get('vendor_slug')
        if vendor_slug:
            queryset = queryset.filter(vendor__slug=vendor_slug)

        # Filter by event slug (for single event lookup)
        slug = self.request.query_params.get('slug')
        if slug:
            queryset = queryset.filter(slug=slug)

        category = self.request.query_params.get('category')
        if category:
            queryset = queryset.filter(category=category)

        search = self.request.query_params.get('search')
        if search:
            queryset = queryset.filter(
                Q(title__icontains=search) |
                Q(description__icontains=search)
            )

        county = self.request.query_params.get('county')
        if county:
            queryset = queryset.filter(county__iexact=county)

        event_type = self.request.query_params.get('event_type')
        if event_type:
            queryset = queryset.filter(event_type=event_type)

        location_type = self.request.query_params.get('location_type')
        if location_type:
            queryset = queryset.filter(location_type=location_type)

        is_free = self.request.query_params.get('is_free')
        if is_free and is_free.lower() == 'true':
            queryset = queryset.filter(is_free=True)

        # Priority annotation: sponsored > verified > pro > default
        from promotions.utils import annotate_priority
        queryset = annotate_priority(queryset, 'event')

        sort = self.request.query_params.get('sort')
        if sort == 'popular':
            queryset = queryset.annotate(total_likes=Count('likes')).order_by('-priority', '-total_likes')
        elif sort == 'date':
            queryset = queryset.filter(date__gte=timezone.now().date()).order_by('-priority', 'date')
        elif sort == 'views':
            queryset = queryset.order_by('-priority', '-views')
        elif sort == 'price_asc':
            queryset = queryset.order_by('-priority', 'packages__price')
        elif sort == 'price_desc':
            queryset = queryset.order_by('-priority', '-packages__price')
        else:
            queryset = queryset.order_by('-priority', '-created_at')

        return queryset.distinct()


class EventDetailView(APIView):
    """Get event detail by slug (public)"""
    permission_classes = [permissions.AllowAny]

    def get(self, request, slug):
        try:
            event = Event.objects.select_related('vendor', 'vendor__user').prefetch_related('packages').get(slug=slug, status='active')
        except Event.DoesNotExist:
            return Response({'success': False, 'message': 'Event not found'}, status=status.HTTP_404_NOT_FOUND)

        event.views += 1
        event.save(update_fields=['views'])

        serializer = EventDetailSerializer(event, context={'request': request})
        return Response({'success': True, 'data': serializer.data}, status=status.HTTP_200_OK)


class EventDetailByIdView(APIView):
    """Get event detail by ID (public)"""
    permission_classes = [permissions.AllowAny]

    def get(self, request, pk):
        try:
            event = Event.objects.select_related('vendor', 'vendor__user').prefetch_related('packages').get(pk=pk, status='active')
        except Event.DoesNotExist:
            return Response({'success': False, 'message': 'Event not found'}, status=status.HTTP_404_NOT_FOUND)

        event.views += 1
        event.save(update_fields=['views'])

        serializer = EventDetailSerializer(event, context={'request': request})
        return Response({'success': True, 'data': serializer.data}, status=status.HTTP_200_OK)


class VendorEventsPublicView(generics.ListAPIView):
    """List events by a specific vendor (public)"""
    serializer_class = EventSerializer
    permission_classes = [permissions.AllowAny]
    pagination_class = EventPagination

    def get_queryset(self):
        vendor_slug = self.kwargs.get('vendor_slug')
        return Event.objects.filter(
            vendor__slug=vendor_slug,
            status='active'
        ).select_related('vendor', 'vendor__user').prefetch_related('packages')


# ============== DISCOVERY ==============

class UpcomingEventsView(APIView):
    """Get upcoming events"""
    permission_classes = [permissions.AllowAny]

    def get(self, request):
        limit = int(request.query_params.get('limit', 10))
        today = timezone.now().date()

        events = Event.objects.filter(
            status='active',
            date__gte=today
        ).select_related('vendor', 'vendor__user').prefetch_related('packages').order_by('date')[:limit]

        serializer = EventSerializer(events, many=True, context={'request': request})
        return Response({'success': True, 'data': serializer.data})


class PopularEventsView(APIView):
    """Get popular events by likes/views"""
    permission_classes = [permissions.AllowAny]

    def get(self, request):
        limit = int(request.query_params.get('limit', 10))
        events = Event.objects.filter(status='active').annotate(
            total_likes=Count('likes')
        ).order_by('-total_likes', '-views').select_related('vendor', 'vendor__user').prefetch_related('packages')[:limit]

        serializer = EventSerializer(events, many=True, context={'request': request})
        return Response({'success': True, 'data': serializer.data})


class NearbyEventsView(APIView):
    """Get events near user by county"""
    permission_classes = [permissions.AllowAny]

    def get(self, request):
        county = request.query_params.get('county')
        if not county and request.user.is_authenticated:
            county = request.user.county

        if not county:
            return Response({'success': False, 'message': 'County is required'}, status=status.HTTP_400_BAD_REQUEST)

        events = Event.objects.filter(
            status='active',
            county__iexact=county
        ).select_related('vendor', 'vendor__user').prefetch_related('packages').order_by('-created_at')[:50]

        serializer = EventSerializer(events, many=True, context={'request': request})
        return Response({'success': True, 'data': serializer.data, 'county': county})


class EventCategoriesView(APIView):
    """Get event categories with counts"""
    permission_classes = [permissions.AllowAny]

    def get(self, request):
        categories = Event.objects.filter(status='active').values('category').annotate(
            count=Count('id')
        ).order_by('-count')

        category_labels = dict(Event.EVENT_CATEGORY_CHOICES)
        data = [
            {
                'key': cat['category'],
                'label': category_labels.get(cat['category'], cat['category']),
                'count': cat['count'],
            }
            for cat in categories
        ]
        return Response({'success': True, 'data': data})


# ============== VENDOR MANAGEMENT ==============

class VendorMyEventsView(APIView):
    """List vendor's own events"""
    permission_classes = [IsVendor]

    def get(self, request):
        events = Event.objects.filter(
            vendor=request.user.vendor_profile
        ).exclude(status='deleted').select_related('vendor', 'vendor__user').prefetch_related('packages')
        serializer = EventSerializer(events, many=True, context={'request': request})
        return Response({'success': True, 'data': serializer.data}, status=status.HTTP_200_OK)


class EventCreateView(generics.CreateAPIView):
    """Create a new event"""
    serializer_class = EventCreateSerializer
    permission_classes = [IsVendor]
    parser_classes = [MultiPartParser, FormParser]

    def create(self, request, *args, **kwargs):
        data = request.data.copy()

        # Parse JSON fields
        if 'packages' in data and isinstance(data['packages'], str):
            try:
                data['packages'] = json.loads(data['packages'])
            except json.JSONDecodeError:
                data['packages'] = []

        if 'recurring_days' in data and isinstance(data['recurring_days'], str):
            try:
                data['recurring_days'] = json.loads(data['recurring_days'])
            except json.JSONDecodeError:
                data['recurring_days'] = []

        # Convert is_free to boolean
        if 'is_free' in data:
            data['is_free'] = str(data['is_free']).lower() in ('true', '1', 'yes')

        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=True)
        event = serializer.save()
        output = EventSerializer(event, context={'request': request})
        return Response({'success': True, 'data': output.data}, status=status.HTTP_201_CREATED)


class EventUpdateView(APIView):
    """Update an event"""
    permission_classes = [IsVendor]
    parser_classes = [MultiPartParser, FormParser]

    def put(self, request, pk):
        try:
            event = Event.objects.get(pk=pk, vendor=request.user.vendor_profile)
        except Event.DoesNotExist:
            return Response({'success': False, 'message': 'Event not found'}, status=status.HTTP_404_NOT_FOUND)

        data = request.data.copy()

        # Parse JSON fields
        if 'packages' in data and isinstance(data['packages'], str):
            try:
                data['packages'] = json.loads(data['packages'])
            except json.JSONDecodeError:
                data['packages'] = []

        if 'deleted_packages' in data and isinstance(data['deleted_packages'], str):
            try:
                data['deleted_packages'] = json.loads(data['deleted_packages'])
            except json.JSONDecodeError:
                data['deleted_packages'] = []

        if 'recurring_days' in data and isinstance(data['recurring_days'], str):
            try:
                data['recurring_days'] = json.loads(data['recurring_days'])
            except json.JSONDecodeError:
                data['recurring_days'] = []

        # Convert is_free to boolean
        if 'is_free' in data:
            data['is_free'] = str(data['is_free']).lower() in ('true', '1', 'yes')

        serializer = EventUpdateSerializer(event, data=data, partial=True, context={'request': request})
        serializer.is_valid(raise_exception=True)
        event = serializer.save()
        output = EventSerializer(event, context={'request': request})
        return Response({'success': True, 'data': output.data}, status=status.HTTP_200_OK)

    def patch(self, request, pk):
        return self.put(request, pk)


class EventDeleteView(APIView):
    """Soft delete an event"""
    permission_classes = [IsVendor]

    def delete(self, request, pk):
        try:
            event = Event.objects.get(pk=pk, vendor=request.user.vendor_profile)
        except Event.DoesNotExist:
            return Response({'success': False, 'message': 'Event not found'}, status=status.HTTP_404_NOT_FOUND)

        event.status = 'deleted'
        event.save(update_fields=['status'])

        return Response({'success': True, 'message': 'Event deleted'}, status=status.HTTP_200_OK)


# ============== PACKAGE MANAGEMENT ==============

class EventPackageAddView(APIView):
    """Add a package to an event"""
    permission_classes = [IsVendor]

    def post(self, request, event_id):
        try:
            event = Event.objects.get(pk=event_id, vendor=request.user.vendor_profile)
        except Event.DoesNotExist:
            return Response({'success': False, 'message': 'Event not found'}, status=status.HTTP_404_NOT_FOUND)

        serializer = EventPackageSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        package = serializer.save(event=event)

        return Response({'success': True, 'data': EventPackageSerializer(package).data}, status=status.HTTP_201_CREATED)


class EventPackageUpdateView(APIView):
    """Update a package"""
    permission_classes = [IsVendor]

    def put(self, request, pk):
        try:
            package = EventPackage.objects.select_related('event__vendor').get(
                pk=pk,
                event__vendor=request.user.vendor_profile
            )
        except EventPackage.DoesNotExist:
            return Response({'success': False, 'message': 'Package not found'}, status=status.HTTP_404_NOT_FOUND)

        serializer = EventPackageSerializer(package, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        package = serializer.save()

        return Response({'success': True, 'data': EventPackageSerializer(package).data}, status=status.HTTP_200_OK)

    def patch(self, request, pk):
        return self.put(request, pk)


class EventPackageDeleteView(APIView):
    """Delete a package"""
    permission_classes = [IsVendor]

    def delete(self, request, pk):
        try:
            package = EventPackage.objects.select_related('event__vendor').get(
                pk=pk,
                event__vendor=request.user.vendor_profile
            )
        except EventPackage.DoesNotExist:
            return Response({'success': False, 'message': 'Package not found'}, status=status.HTTP_404_NOT_FOUND)

        package.delete()
        return Response({'success': True, 'message': 'Package deleted'}, status=status.HTTP_200_OK)


# ============== SOCIAL ==============

class EventLikeToggleView(APIView):
    """Toggle like on an event"""
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, event_id):
        try:
            event = Event.objects.get(id=event_id, status='active')
        except Event.DoesNotExist:
            return Response({'success': False, 'message': 'Event not found'}, status=status.HTTP_404_NOT_FOUND)

        like, created = EventLike.objects.get_or_create(user=request.user, event=event)
        if not created:
            like.delete()
            return Response({'success': True, 'liked': False, 'likes_count': event.likes.count()})
        return Response({'success': True, 'liked': True, 'likes_count': event.likes.count()})


class EventLikeStatusView(APIView):
    """Check if user liked an event"""
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request, event_id):
        is_liked = EventLike.objects.filter(user=request.user, event_id=event_id).exists()
        return Response({'success': True, 'is_liked': is_liked})


class EventSaveToggleView(APIView):
    """Toggle save on an event"""
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, event_id):
        try:
            event = Event.objects.get(id=event_id, status='active')
        except Event.DoesNotExist:
            return Response({'success': False, 'message': 'Event not found'}, status=status.HTTP_404_NOT_FOUND)

        save, created = EventSave.objects.get_or_create(user=request.user, event=event)
        if not created:
            save.delete()
            return Response({'success': True, 'saved': False})
        return Response({'success': True, 'saved': True})


class EventUnsaveView(APIView):
    """Remove event from saved"""
    permission_classes = [permissions.IsAuthenticated]

    def delete(self, request, event_id):
        try:
            save = EventSave.objects.get(user=request.user, event_id=event_id)
            save.delete()
            return Response({'success': True, 'message': 'Event unsaved'})
        except EventSave.DoesNotExist:
            return Response({'success': True, 'message': 'Event was not saved'})


# ============== MALL EVENTS ==============

class MallEventsView(APIView):
    """Get events for a specific mall"""
    permission_classes = [permissions.AllowAny]

    def get(self, request, mall_slug):
        from groups.models import Group
        try:
            group = Group.objects.get(slug=mall_slug, is_active=True)
        except Group.DoesNotExist:
            return Response({'success': False, 'message': 'Mall not found'}, status=status.HTTP_404_NOT_FOUND)

        from promotions.utils import annotate_priority
        events = annotate_priority(
            Event.objects.filter(
                group=group,
                status='active'
            ).select_related('vendor', 'vendor__user').prefetch_related('packages'),
            'event'
        ).order_by('-priority', '-created_at')

        serializer = EventSerializer(events, many=True, context={'request': request})
        return Response({'success': True, 'data': serializer.data})


# ============== ADMIN ==============

class AdminEventsListView(APIView):
    """Admin: list all events"""
    permission_classes = [IsAdmin]

    def get(self, request):
        queryset = Event.objects.all().select_related('vendor', 'vendor__user').prefetch_related('packages')

        search = request.query_params.get('search')
        if search:
            queryset = queryset.filter(
                Q(title__icontains=search) |
                Q(vendor__shop_name__icontains=search)
            )

        category = request.query_params.get('category')
        if category:
            queryset = queryset.filter(category=category)

        status_filter = request.query_params.get('status')
        if status_filter:
            queryset = queryset.filter(status=status_filter)

        paginator = EventPagination()
        page = paginator.paginate_queryset(queryset, request)
        if page is not None:
            serializer = EventSerializer(page, many=True, context={'request': request})
            paginated = paginator.get_paginated_response(serializer.data)
            return Response({
                'success': True,
                'data': paginated.data['results'],
                'count': paginated.data['count'],
                'next': paginated.data['next'],
                'previous': paginated.data['previous'],
            })
        serializer = EventSerializer(queryset, many=True, context={'request': request})
        return Response({'success': True, 'data': serializer.data})


class AdminEventToggleView(APIView):
    """Admin: toggle event status"""
    permission_classes = [IsAdmin]

    def post(self, request, pk):
        try:
            event = Event.objects.get(pk=pk)
        except Event.DoesNotExist:
            return Response({'success': False, 'message': 'Event not found'}, status=status.HTTP_404_NOT_FOUND)

        new_status = request.data.get('status', 'active' if event.status == 'cancelled' else 'cancelled')
        event.status = new_status
        event.save(update_fields=['status'])
        return Response({'success': True, 'message': f'Event status changed to {new_status}', 'status': new_status})


class AdminEventDeleteView(APIView):
    """Admin: delete an event"""
    permission_classes = [IsAdmin]

    def delete(self, request, pk):
        try:
            event = Event.objects.get(pk=pk)
        except Event.DoesNotExist:
            return Response({'success': False, 'message': 'Event not found'}, status=status.HTTP_404_NOT_FOUND)

        event.status = 'deleted'
        event.save(update_fields=['status'])

        return Response({'success': True, 'message': 'Event deleted'})
