"""
Photo upload and management views for ThrillWiki.

Security Note:
    All uploads are validated for file type, size, and content before being saved.
    Rate limiting is enforced to prevent abuse.
"""

from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from django.contrib.auth.decorators import login_required
from django.contrib.contenttypes.models import ContentType
from django.shortcuts import get_object_or_404
import json
import logging

from .models import Photo
from apps.core.utils.file_scanner import (
    validate_image_upload,
    FileValidationError,
    check_upload_rate_limit,
    increment_upload_count,
)

logger = logging.getLogger(__name__)


@login_required
@require_http_methods(["POST"])
def upload_photo(request):
    """
    Handle photo upload for any model.

    Security measures:
    - Rate limiting to prevent abuse
    - File type validation (extension, MIME type, magic number)
    - File size validation
    - Image integrity validation
    - Permission checks
    """
    try:
        # Security: Check rate limiting before processing upload
        is_allowed, rate_limit_message = check_upload_rate_limit(request.user.id)
        if not is_allowed:
            logger.warning(
                f"User {request.user} exceeded upload rate limit"
            )
            return JsonResponse(
                {"error": rate_limit_message},
                status=429,  # Too Many Requests
            )

        # Get app label, model, and object ID
        app_label = request.POST.get("app_label")
        model = request.POST.get("model")
        object_id = request.POST.get("object_id")

        # Log received data (don't log file contents for security)
        logger.debug(
            f"Received upload request - app_label: {app_label}, model: {model}, object_id: {object_id}"
        )

        # Validate required fields
        missing_fields = []
        if not app_label:
            missing_fields.append("app_label")
        if not model:
            missing_fields.append("model")
        if not object_id:
            missing_fields.append("object_id")
        if "image" not in request.FILES:
            missing_fields.append("image")

        if missing_fields:
            return JsonResponse(
                {"error": f'Missing required fields: {", ".join(missing_fields)}'},
                status=400,
            )

        # Security: Validate uploaded file before processing
        uploaded_file = request.FILES["image"]
        try:
            validate_image_upload(uploaded_file)
        except FileValidationError as e:
            logger.warning(
                f"User {request.user} attempted to upload invalid file: {str(e)}"
            )
            return JsonResponse(
                {"error": str(e)},
                status=400,
            )

        # Get content type
        try:
            content_type = ContentType.objects.get(
                app_label=app_label.lower(), model=model.lower()
            )
        except ContentType.DoesNotExist:
            return JsonResponse(
                {"error": f"Invalid content type: {app_label}.{model}"},
                status=400,
            )

        # Get the object instance
        try:
            obj = content_type.get_object_for_this_type(pk=object_id)
        except Exception as e:
            return JsonResponse(
                {
                    "error": f"Object not found: {app_label}.{model} with id {object_id}. Error: {
                        str(e)}"
                },
                status=404,
            )

        # Check if user has permission to add photos
        if not request.user.has_perm("media.add_photo"):
            logger.warning(
                f"User {
                    request.user} attempted to upload photo without permission"
            )
            return JsonResponse(
                {"error": "You do not have permission to upload photos"},
                status=403,
            )

        # Determine if the photo should be auto-approved
        is_approved = (
            request.user.is_superuser
            or request.user.is_staff
            or request.user.groups.filter(name="Moderators").exists()
        )

        # Create the photo
        photo = Photo.objects.create(
            image=uploaded_file,
            content_type=content_type,
            object_id=obj.pk,
            uploaded_by=request.user,
            is_primary=not Photo.objects.filter(
                content_type=content_type, object_id=obj.pk
            ).exists(),
            is_approved=is_approved,
        )

        # Security: Increment upload count for rate limiting
        increment_upload_count(request.user.id)

        return JsonResponse(
            {
                "id": photo.pk,
                "url": photo.image.url,
                "caption": photo.caption,
                "is_primary": photo.is_primary,
                "is_approved": photo.is_approved,
            }
        )

    except Exception as e:
        logger.error(f"Error in upload_photo: {str(e)}", exc_info=True)
        return JsonResponse(
            {"error": "An error occurred while uploading the photo"},
            status=400,
        )


@login_required
@require_http_methods(["POST"])
def set_primary_photo(request, photo_id):
    """Set a photo as primary"""
    try:
        photo = get_object_or_404(Photo, pk=photo_id)

        # Check if user has permission to edit photos
        if not request.user.has_perm("media.change_photo"):
            return JsonResponse(
                {"error": "You do not have permission to edit photos"},
                status=403,
            )

        # Set this photo as primary
        photo.is_primary = True
        photo.save()  # This will automatically unset other primary photos

        return JsonResponse({"status": "success"})

    except Exception as e:
        logger.error(f"Error in set_primary_photo: {str(e)}", exc_info=True)
        return JsonResponse({"error": str(e)}, status=400)


@login_required
@require_http_methods(["POST"])
def update_caption(request, photo_id):
    """Update a photo's caption"""
    try:
        photo = get_object_or_404(Photo, pk=photo_id)

        # Check if user has permission to edit photos
        if not request.user.has_perm("media.change_photo"):
            return JsonResponse(
                {"error": "You do not have permission to edit photos"},
                status=403,
            )

        # Update caption
        data = json.loads(request.body)
        photo.caption = data.get("caption", "")
        photo.save()

        return JsonResponse({"id": photo.pk, "caption": photo.caption})

    except Exception as e:
        logger.error(f"Error in update_caption: {str(e)}", exc_info=True)
        return JsonResponse({"error": str(e)}, status=400)


@login_required
@require_http_methods(["DELETE"])
def delete_photo(request, photo_id):
    """Delete a photo"""
    try:
        photo = get_object_or_404(Photo, pk=photo_id)

        # Check if user has permission to delete photos
        if not request.user.has_perm("media.delete_photo"):
            return JsonResponse(
                {"error": "You do not have permission to delete photos"},
                status=403,
            )

        photo.delete()
        return JsonResponse({"status": "success"})

    except Exception as e:
        logger.error(f"Error in delete_photo: {str(e)}", exc_info=True)
        return JsonResponse({"error": str(e)}, status=400)
