from rest_framework import serializers
from producers_products.models.producers_products import ProductsReview, ProducersProducts
from common.storage import StorageFactory
from common.storage.exceptions import StorageError
from common.validators.image_validator import ImageValidator
from common.validators.video_validator import VideoValidator


class ProductsReviewSerializer(serializers.ModelSerializer):
    """Product review serializer with storage abstraction support for images and videos"""
    # Override model CharField fields to accept File objects on write operations
    review_image = serializers.FileField(write_only=True, required=False, allow_null=True)
    review_video = serializers.FileField(write_only=True, required=False, allow_null=True)
    
    # Read-only fields for URL generation
    product_name = serializers.CharField(source='product.name', read_only=True)
    review_image_url = serializers.SerializerMethodField(read_only=True)
    review_video_url = serializers.SerializerMethodField(read_only=True)
    review_video_streaming_url = serializers.SerializerMethodField(read_only=True)
    review_video_thumbnail_url = serializers.SerializerMethodField(read_only=True)
    media_type = serializers.SerializerMethodField(read_only=True)

    def __init__(self, *args, **kwargs):
        """
        Initialize serializer with storage backend and validators.
        """
        super().__init__(*args, **kwargs)
        self.storage_backend = StorageFactory.get_storage_backend()
        self.image_validator = ImageValidator(
            max_size_bytes=5 * 1024 * 1024,  # 5MB
            allowed_types=['image/jpeg', 'image/jpg', 'image/png', 'image/webp']
        )
        self.video_validator = VideoValidator(
            max_size_bytes=100 * 1024 * 1024,  # 100MB
            allowed_types=['video/mp4', 'video/quicktime', 'video/webm'],
            max_duration_seconds=300  # 5 minutes
        )

    class Meta:
        model = ProductsReview
        fields = [
            'id',
            'review_star',
            'message',
            'review_image',
            'review_image_url',
            'review_video',
            'review_video_url',
            'review_video_streaming_url',
            'review_video_thumbnail_url',
            'video_duration',
            'media_type',
            'product',
            'product_name',
            'is_flagged_review',
            'created_at'
        ]
        read_only_fields = ['id', 'created_at', 'product_name', 'video_duration']
    
    def validate(self, attrs):
        """
        Ensure only image OR video, not both.
        """
        review_image = attrs.get('review_image')
        review_video = attrs.get('review_video')
        
        if review_image and review_video:
            raise serializers.ValidationError(
                "Cannot upload both image and video. Please choose one."
            )
        
        return attrs
    
    def validate_review_star(self, value):
        """Ensure review star is between 1 and 5"""
        if value < 1 or value > 5:
            raise serializers.ValidationError("Review star must be between 1 and 5")
        return value

    def validate_review_image(self, value):
        """
        Validate review image using the new ImageValidator.
        """
        if not value:
            return value
        
        try:
            self.image_validator.validate(value)
            return value
        except serializers.ValidationError:
            raise
        except Exception as e:
            raise serializers.ValidationError(f"Image validation failed: {str(e)}")

    def validate_review_video(self, value):
        """
        Validate review video using the VideoValidator.
        """
        if not value:
            return value
        
        try:
            self.video_validator.validate(value)
            return value
        except serializers.ValidationError:
            raise
        except Exception as e:
            raise serializers.ValidationError(f"Video validation failed: {str(e)}")

    def get_media_type(self, obj):
        """Return 'image', 'video', or None"""
        if obj.review_video:
            return 'video'
        elif obj.review_image:
            return 'image'
        return None

    def get_review_image_url(self, obj):
        """
        Get review image URL using storage backend.
        """
        if not obj.review_image:
            return None
        
        try:
            url = self.storage_backend.get_url(str(obj.review_image))
            
            # For filesystem storage, we need to build absolute URI
            if StorageFactory.is_filesystem_backend():
                request = self.context.get("request")
                return request.build_absolute_uri(url) if request else url
            
            # For Cloudinary, URL is already absolute
            return url
            
        except Exception:
            # Fallback to legacy behavior if storage backend fails
            request = self.context.get("request")
            url = obj.review_image.url if hasattr(obj.review_image, 'url') else str(obj.review_image)
            return request.build_absolute_uri(url) if request else url

    def get_review_video_url(self, obj):
        """Get progressive video URL"""
        if not obj.review_video:
            return None
        
        try:
            return self.storage_backend.get_video_url(str(obj.review_video))
        except Exception:
            return None
    
    def get_review_video_streaming_url(self, obj):
        """Get HLS streaming URL"""
        if not obj.review_video:
            return None
        
        try:
            return self.storage_backend.get_streaming_url(str(obj.review_video))
        except Exception:
            return None
    
    def get_review_video_thumbnail_url(self, obj):
        """Get video thumbnail URL"""
        if not obj.review_video:
            return None
        
        try:
            return self.storage_backend.get_thumbnail_url(str(obj.review_video))
        except Exception:
            return None

    def create(self, validated_data):
        """
        Create product review with image or video upload using storage backend.
        """
        request = self.context.get("request")
        review_image = validated_data.get("review_image")
        review_video = validated_data.get("review_video")
        
        # Handle image upload
        if review_image:
            try:
                identifier = self.storage_backend.upload(review_image, "reviews/product")
                validated_data["review_image"] = identifier
                
            except StorageError as e:
                raise serializers.ValidationError({
                    "review_image": f"Failed to upload image: {str(e)}"
                })
            except Exception as e:
                raise serializers.ValidationError({
                    "review_image": f"Unexpected error during image upload: {str(e)}"
                })
        
        # Handle video upload
        if review_video:
            try:
                identifier = self.storage_backend.upload_video(review_video, "reviews/product")
                validated_data["review_video"] = identifier
                
                metadata = self.storage_backend.get_video_metadata(identifier)
                validated_data["video_duration"] = int(metadata.get('duration', 0))
                
            except StorageError as e:
                raise serializers.ValidationError({
                    "review_video": f"Failed to upload video: {str(e)}"
                })
            except Exception as e:
                raise serializers.ValidationError({
                    "review_video": f"Unexpected error during video upload: {str(e)}"
                })
        
        # Set user from request
        if request and hasattr(request, "user"):
            validated_data["created_by"] = request.user
            
        return super().create(validated_data)

    def update(self, instance, validated_data):
        """
        Update product review with image or video upload using storage backend.
        """
        review_image = validated_data.get("review_image")
        review_video = validated_data.get("review_video")
        old_image_identifier = str(instance.review_image) if instance.review_image else None
        old_video_identifier = str(instance.review_video) if instance.review_video else None
        
        # Handle image upload
        if review_image:
            try:
                identifier = self.storage_backend.upload(review_image, "reviews/product")
                validated_data["review_image"] = identifier
                
                # Clear video fields if replacing video with image
                if old_video_identifier:
                    validated_data["review_video"] = None
                    validated_data["video_duration"] = None
                    try:
                        self.storage_backend.delete(old_video_identifier)
                    except Exception:
                        pass
                
                # Delete old image if it exists
                if old_image_identifier:
                    try:
                        self.storage_backend.delete(old_image_identifier)
                    except Exception:
                        pass
                
            except StorageError as e:
                raise serializers.ValidationError({
                    "review_image": f"Failed to upload image: {str(e)}"
                })
            except Exception as e:
                raise serializers.ValidationError({
                    "review_image": f"Unexpected error during image upload: {str(e)}"
                })
        
        # Handle video upload
        if review_video:
            try:
                identifier = self.storage_backend.upload_video(review_video, "reviews/product")
                validated_data["review_video"] = identifier
                
                metadata = self.storage_backend.get_video_metadata(identifier)
                validated_data["video_duration"] = int(metadata.get('duration', 0))
                
                # Clear image field if replacing image with video
                if old_image_identifier:
                    validated_data["review_image"] = None
                    try:
                        self.storage_backend.delete(old_image_identifier)
                    except Exception:
                        pass
                
                # Delete old video if it exists
                if old_video_identifier:
                    try:
                        self.storage_backend.delete(old_video_identifier)
                    except Exception:
                        pass
                
            except StorageError as e:
                raise serializers.ValidationError({
                    "review_video": f"Failed to upload video: {str(e)}"
                })
            except Exception as e:
                raise serializers.ValidationError({
                    "review_video": f"Unexpected error during video upload: {str(e)}"
                })
        
        return super().update(instance, validated_data)
