"""
Ride photo API views for ThrillWiki API v1 (nested under parks).

This module contains ride photo ViewSet following the parks pattern for domain consistency.
Provides CRUD operations for ride photos nested under parks/{park_slug}/rides/{ride_slug}/photos/
"""

import logging
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    pass

from django.core.exceptions import PermissionDenied
from django.utils import timezone
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema, extend_schema_view
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.exceptions import NotFound, ValidationError
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet

from apps.api.v1.rides.serializers import (
    RidePhotoApprovalInputSerializer,
    RidePhotoCreateInputSerializer,
    RidePhotoListOutputSerializer,
    RidePhotoOutputSerializer,
    RidePhotoStatsOutputSerializer,
    RidePhotoUpdateInputSerializer,
)
from apps.core.utils import capture_and_log
from apps.parks.models import Park
from apps.rides.models import Ride
from apps.rides.models.media import RidePhoto
from apps.rides.services.media_service import RideMediaService

logger = logging.getLogger(__name__)


@extend_schema_view(
    list=extend_schema(
        summary="List ride photos",
        description="Retrieve a paginated list of ride photos with filtering capabilities.",
        responses={200: RidePhotoListOutputSerializer(many=True)},
        tags=["Ride Photos"],
    ),
    create=extend_schema(
        summary="Upload ride photo",
        description="Upload a new photo for a ride. Requires authentication.",
        request=RidePhotoCreateInputSerializer,
        responses={
            201: RidePhotoOutputSerializer,
            400: OpenApiTypes.OBJECT,
            401: OpenApiTypes.OBJECT,
        },
        tags=["Ride Photos"],
    ),
    retrieve=extend_schema(
        summary="Get ride photo details",
        description="Retrieve detailed information about a specific ride photo.",
        responses={
            200: RidePhotoOutputSerializer,
            404: OpenApiTypes.OBJECT,
        },
        tags=["Ride Photos"],
    ),
    update=extend_schema(
        summary="Update ride photo",
        description="Update ride photo information. Requires authentication and ownership or admin privileges.",
        request=RidePhotoUpdateInputSerializer,
        responses={
            200: RidePhotoOutputSerializer,
            400: OpenApiTypes.OBJECT,
            401: OpenApiTypes.OBJECT,
            403: OpenApiTypes.OBJECT,
            404: OpenApiTypes.OBJECT,
        },
        tags=["Ride Photos"],
    ),
    partial_update=extend_schema(
        summary="Partially update ride photo",
        description="Partially update ride photo information. Requires authentication and ownership or admin privileges.",
        request=RidePhotoUpdateInputSerializer,
        responses={
            200: RidePhotoOutputSerializer,
            400: OpenApiTypes.OBJECT,
            401: OpenApiTypes.OBJECT,
            403: OpenApiTypes.OBJECT,
            404: OpenApiTypes.OBJECT,
        },
        tags=["Ride Photos"],
    ),
    destroy=extend_schema(
        summary="Delete ride photo",
        description="Delete a ride photo. Requires authentication and ownership or admin privileges.",
        responses={
            204: None,
            401: OpenApiTypes.OBJECT,
            403: OpenApiTypes.OBJECT,
            404: OpenApiTypes.OBJECT,
        },
        tags=["Ride Photos"],
    ),
)
class RidePhotoViewSet(ModelViewSet):
    """
    ViewSet for managing ride photos with full CRUD operations (nested under parks).

    Provides CRUD operations for ride photos with proper permission checking.
    Uses RideMediaService for business logic operations.
    Includes advanced features like bulk approval and statistics.
    """

    lookup_field = "id"

    def get_permissions(self):
        """Set permissions based on action."""
        permission_classes = [AllowAny] if self.action in ["list", "retrieve", "stats"] else [IsAuthenticated]
        return [permission() for permission in permission_classes]

    def get_queryset(self):
        """Get photos for the current ride with optimized queries."""
        queryset = RidePhoto.objects.select_related("ride", "ride__park", "ride__park__operator", "uploaded_by")

        # Filter by park and ride from URL kwargs
        park_slug = self.kwargs.get("park_slug")
        ride_slug = self.kwargs.get("ride_slug")

        if park_slug and ride_slug:
            try:
                park, _ = Park.get_by_slug(park_slug)
                ride, _ = Ride.get_by_slug(ride_slug, park=park)
                queryset = queryset.filter(ride=ride)
            except (Park.DoesNotExist, Ride.DoesNotExist):
                # Return empty queryset if park or ride not found
                return queryset.none()

        return queryset.order_by("-created_at")

    def get_serializer_class(self):
        """Return appropriate serializer based on action."""
        if self.action == "list":
            return RidePhotoListOutputSerializer
        elif self.action == "create":
            return RidePhotoCreateInputSerializer
        elif self.action in ["update", "partial_update"]:
            return RidePhotoUpdateInputSerializer
        else:
            return RidePhotoOutputSerializer

    def perform_create(self, serializer):
        """Create a new ride photo using RideMediaService."""
        park_slug = self.kwargs.get("park_slug")
        ride_slug = self.kwargs.get("ride_slug")

        if not park_slug or not ride_slug:
            raise ValidationError("Park and ride slugs are required")

        try:
            park, _ = Park.get_by_slug(park_slug)
            ride, _ = Ride.get_by_slug(ride_slug, park=park)
        except Park.DoesNotExist:
            raise NotFound("Park not found") from None
        except Ride.DoesNotExist:
            raise NotFound("Ride not found at this park") from None

        try:
            # Use the service to create the photo with proper business logic
            photo = RideMediaService.upload_photo(
                ride=ride,
                image_file=serializer.validated_data["image"],
                user=self.request.user,
                caption=serializer.validated_data.get("caption", ""),
                alt_text=serializer.validated_data.get("alt_text", ""),
                photo_type=serializer.validated_data.get("photo_type", "exterior"),
                is_primary=serializer.validated_data.get("is_primary", False),
                auto_approve=False,  # Default to requiring approval
            )

            # Set the instance for the serializer response
            serializer.instance = photo

            logger.info(f"Created ride photo {photo.id} for ride {ride.name} by user {self.request.user.username}")

        except Exception as e:
            capture_and_log(e, 'Create ride photo', source='api', request=self.request)
            raise ValidationError(f"Failed to create photo: {str(e)}") from None

    def perform_update(self, serializer):
        """Update ride photo with permission checking."""
        instance = self.get_object()

        # Check permissions - allow owner or staff
        if not (self.request.user == instance.uploaded_by or getattr(self.request.user, "is_staff", False)):
            raise PermissionDenied("You can only edit your own photos or be an admin.")

        # Handle primary photo logic using service
        if serializer.validated_data.get("is_primary", False):
            try:
                RideMediaService.set_primary_photo(ride=instance.ride, photo=instance)
                # Remove is_primary from validated_data since service handles it
                if "is_primary" in serializer.validated_data:
                    del serializer.validated_data["is_primary"]
            except Exception as e:
                capture_and_log(e, 'Set primary photo', source='api', request=self.request)
                raise ValidationError(f"Failed to set primary photo: {str(e)}") from None

        try:
            serializer.save()
            logger.info(f"Updated ride photo {instance.id} by user {self.request.user.username}")
        except Exception as e:
            capture_and_log(e, 'Update ride photo', source='api', request=self.request)
            raise ValidationError(f"Failed to update photo: {str(e)}") from None

    def perform_destroy(self, instance):
        """Delete ride photo with permission checking."""
        # Check permissions - allow owner or staff
        if not (self.request.user == instance.uploaded_by or getattr(self.request.user, "is_staff", False)):
            raise PermissionDenied("You can only delete your own photos or be an admin.")

        try:
            # Delete from Cloudflare first if image exists
            if instance.image:
                try:
                    from django_cloudflareimages_toolkit.services import CloudflareImagesService

                    service = CloudflareImagesService()
                    service.delete_image(instance.image)
                    logger.info(f"Successfully deleted ride photo from Cloudflare: {instance.image.cloudflare_id}")
                except Exception as e:
                    capture_and_log(e, 'Delete ride photo from Cloudflare', source='api', request=self.request, severity='low')
                    # Continue with database deletion even if Cloudflare deletion fails

            RideMediaService.delete_photo(instance, deleted_by=self.request.user)

            logger.info(f"Deleted ride photo {instance.id} by user {self.request.user.username}")
        except Exception as e:
            capture_and_log(e, 'Delete ride photo', source='api', request=self.request)
            raise ValidationError(f"Failed to delete photo: {str(e)}") from None

    @extend_schema(
        summary="Set photo as primary",
        description="Set this photo as the primary photo for the ride",
        responses={
            200: OpenApiTypes.OBJECT,
            400: OpenApiTypes.OBJECT,
            403: OpenApiTypes.OBJECT,
            404: OpenApiTypes.OBJECT,
        },
        tags=["Ride Photos"],
    )
    @action(detail=True, methods=["post"])
    def set_primary(self, request, **kwargs):
        """Set this photo as the primary photo for the ride."""
        photo = self.get_object()

        # Check permissions - allow owner or staff
        if not (request.user == photo.uploaded_by or getattr(request.user, "is_staff", False)):
            raise PermissionDenied("You can only modify your own photos or be an admin.")

        try:
            success = RideMediaService.set_primary_photo(ride=photo.ride, photo=photo)

            if success:
                # Refresh the photo instance
                photo.refresh_from_db()
                serializer = self.get_serializer(photo)

                return Response(
                    {
                        "detail": "Photo set as primary successfully",
                        "photo": serializer.data,
                    },
                    status=status.HTTP_200_OK,
                )
            else:
                return Response(
                    {"detail": "Failed to set primary photo"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

        except Exception as e:
            capture_and_log(e, 'Set primary photo', source='api', request=request)
            return Response(
                {"detail": f"Failed to set primary photo: {str(e)}"},
                status=status.HTTP_400_BAD_REQUEST,
            )

    @extend_schema(
        summary="Bulk approve/reject photos",
        description="Bulk approve or reject multiple ride photos (admin only)",
        request=RidePhotoApprovalInputSerializer,
        responses={
            200: OpenApiTypes.OBJECT,
            400: OpenApiTypes.OBJECT,
            403: OpenApiTypes.OBJECT,
        },
        tags=["Ride Photos"],
    )
    @action(detail=False, methods=["post"], permission_classes=[IsAuthenticated])
    def bulk_approve(self, request, **kwargs):
        """Bulk approve or reject multiple photos (admin only)."""
        if not getattr(request.user, "is_staff", False):
            raise PermissionDenied("Only administrators can approve photos.")

        serializer = RidePhotoApprovalInputSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        validated_data = getattr(serializer, "validated_data", {})
        photo_ids = validated_data.get("photo_ids")
        approve = validated_data.get("approve")

        park_slug = self.kwargs.get("park_slug")
        ride_slug = self.kwargs.get("ride_slug")

        if photo_ids is None or approve is None:
            return Response(
                {"detail": "Missing required fields: photo_ids and/or approve."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            # Filter photos to only those belonging to this ride
            photos_queryset = RidePhoto.objects.filter(id__in=photo_ids)
            if park_slug and ride_slug:
                park, _ = Park.get_by_slug(park_slug)
                ride, _ = Ride.get_by_slug(ride_slug, park=park)
                photos_queryset = photos_queryset.filter(ride=ride)

            updated_count = photos_queryset.update(is_approved=approve)

            return Response(
                {
                    "detail": f"Successfully {'approved' if approve else 'rejected'} {updated_count} photos",
                    "updated_count": updated_count,
                },
                status=status.HTTP_200_OK,
            )

        except Exception as e:
            capture_and_log(e, 'Bulk photo approval', source='api', request=request)
            return Response(
                {"detail": f"Failed to update photos: {str(e)}"},
                status=status.HTTP_400_BAD_REQUEST,
            )

    @extend_schema(
        summary="Get ride photo statistics",
        description="Get photo statistics for the ride",
        responses={
            200: RidePhotoStatsOutputSerializer,
            404: OpenApiTypes.OBJECT,
            500: OpenApiTypes.OBJECT,
        },
        tags=["Ride Photos"],
    )
    @action(detail=False, methods=["get"])
    def stats(self, request, **kwargs):
        """Get photo statistics for the ride."""
        park_slug = self.kwargs.get("park_slug")
        ride_slug = self.kwargs.get("ride_slug")

        if not park_slug or not ride_slug:
            return Response(
                {"detail": "Park and ride slugs are required"},
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            park, _ = Park.get_by_slug(park_slug)
            ride, _ = Ride.get_by_slug(ride_slug, park=park)
        except Park.DoesNotExist:
            return Response(
                {"detail": "Park not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Ride.DoesNotExist:
            return Response(
                {"detail": "Ride not found at this park"},
                status=status.HTTP_404_NOT_FOUND,
            )

        try:
            stats = RideMediaService.get_photo_stats(ride)
            serializer = RidePhotoStatsOutputSerializer(stats)
            return Response(serializer.data, status=status.HTTP_200_OK)

        except Exception as e:
            capture_and_log(e, 'Get ride photo stats', source='api', request=request)
            return Response(
                {"detail": f"Failed to get photo statistics: {str(e)}"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    @extend_schema(
        summary="Save Cloudflare image as ride photo",
        description="Save a Cloudflare image as a ride photo after direct upload to Cloudflare",
        request=OpenApiTypes.OBJECT,
        responses={
            201: RidePhotoOutputSerializer,
            400: OpenApiTypes.OBJECT,
            401: OpenApiTypes.OBJECT,
            404: OpenApiTypes.OBJECT,
        },
        tags=["Ride Photos"],
    )
    @action(detail=False, methods=["post"])
    def save_image(self, request, **kwargs):
        """Save a Cloudflare image as a ride photo after direct upload to Cloudflare."""
        park_slug = self.kwargs.get("park_slug")
        ride_slug = self.kwargs.get("ride_slug")

        if not park_slug or not ride_slug:
            return Response(
                {"detail": "Park and ride slugs are required"},
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            park, _ = Park.get_by_slug(park_slug)
            ride, _ = Ride.get_by_slug(ride_slug, park=park)
        except Park.DoesNotExist:
            return Response(
                {"detail": "Park not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Ride.DoesNotExist:
            return Response(
                {"detail": "Ride not found at this park"},
                status=status.HTTP_404_NOT_FOUND,
            )

        cloudflare_image_id = request.data.get("cloudflare_image_id")
        if not cloudflare_image_id:
            return Response(
                {"detail": "cloudflare_image_id is required"},
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            # Import CloudflareImage model and service
            from django_cloudflareimages_toolkit.models import CloudflareImage
            from django_cloudflareimages_toolkit.services import CloudflareImagesService

            # Always fetch the latest image data from Cloudflare API
            try:
                # Get image details from Cloudflare API
                service = CloudflareImagesService()
                image_data = service.get_image(cloudflare_image_id)

                if not image_data:
                    return Response(
                        {"detail": "Image not found in Cloudflare"},
                        status=status.HTTP_400_BAD_REQUEST,
                    )

                # Try to find existing CloudflareImage record by cloudflare_id
                cloudflare_image = None
                try:
                    cloudflare_image = CloudflareImage.objects.get(cloudflare_id=cloudflare_image_id)

                    # Update existing record with latest data from Cloudflare
                    cloudflare_image.status = "uploaded"
                    cloudflare_image.uploaded_at = timezone.now()
                    cloudflare_image.metadata = image_data.get("meta", {})
                    # Extract variants from nested result structure
                    cloudflare_image.variants = image_data.get("result", {}).get("variants", [])
                    cloudflare_image.cloudflare_metadata = image_data
                    cloudflare_image.width = image_data.get("width")
                    cloudflare_image.height = image_data.get("height")
                    cloudflare_image.format = image_data.get("format", "")
                    cloudflare_image.save()

                except CloudflareImage.DoesNotExist:
                    # Create new CloudflareImage record from API response
                    cloudflare_image = CloudflareImage.objects.create(
                        cloudflare_id=cloudflare_image_id,
                        user=request.user,
                        status="uploaded",
                        upload_url="",  # Not needed for uploaded images
                        expires_at=timezone.now() + timezone.timedelta(days=365),  # Set far future expiry
                        uploaded_at=timezone.now(),
                        metadata=image_data.get("meta", {}),
                        # Extract variants from nested result structure
                        variants=image_data.get("result", {}).get("variants", []),
                        cloudflare_metadata=image_data,
                        width=image_data.get("width"),
                        height=image_data.get("height"),
                        format=image_data.get("format", ""),
                    )

            except Exception as api_error:
                capture_and_log(api_error, 'Fetch image from Cloudflare API', source='api', request=request)
                return Response(
                    {"detail": f"Failed to fetch image from Cloudflare: {str(api_error)}"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Create the ride photo with the CloudflareImage reference
            photo = RidePhoto.objects.create(
                ride=ride,
                image=cloudflare_image,
                uploaded_by=request.user,
                caption=request.data.get("caption", ""),
                alt_text=request.data.get("alt_text", ""),
                photo_type=request.data.get("photo_type", "exterior"),
                is_primary=request.data.get("is_primary", False),
                is_approved=False,  # Default to requiring approval
            )

            # Handle primary photo logic if requested
            if request.data.get("is_primary", False):
                try:
                    RideMediaService.set_primary_photo(ride=ride, photo=photo)
                except Exception as e:
                    capture_and_log(e, 'Set primary photo for saved image', source='api', request=request, severity='low')
                    # Don't fail the entire operation, just log the error

            serializer = RidePhotoOutputSerializer(photo, context={"request": request})
            return Response(serializer.data, status=status.HTTP_201_CREATED)

        except Exception as e:
            capture_and_log(e, 'Save ride photo', source='api', request=request)
            return Response(
                {"detail": f"Failed to save photo: {str(e)}"},
                status=status.HTTP_400_BAD_REQUEST,
            )
