"""
Photo management API endpoints.

Provides endpoints for photo upload, management, moderation, and entity attachment.
"""

import logging
from typing import List, Optional
from uuid import UUID

from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError as DjangoValidationError
from django.db.models import Q, Count, Sum
from django.http import HttpRequest
from ninja import Router, File, Form
from ninja.files import UploadedFile
from ninja.pagination import paginate

from api.v1.schemas import (
    PhotoOut,
    PhotoListOut,
    PhotoUpdate,
    PhotoUploadResponse,
    PhotoModerateRequest,
    PhotoReorderRequest,
    PhotoAttachRequest,
    PhotoStatsOut,
    MessageSchema,
    ErrorSchema,
)
from apps.media.models import Photo
from apps.media.services import PhotoService, CloudFlareError
from apps.media.validators import validate_image
from apps.users.permissions import jwt_auth, require_moderator, require_admin
from apps.entities.models import Park, Ride, Company, RideModel

logger = logging.getLogger(__name__)

router = Router(tags=["Photos"])
photo_service = PhotoService()


# ============================================================================
# Helper Functions
# ============================================================================

def serialize_photo(photo: Photo) -> dict:
    """
    Serialize a Photo instance to dict for API response.
    
    Args:
        photo: Photo instance
        
    Returns:
        Dict with photo data
    """
    # Get entity info if attached
    entity_type = None
    entity_id = None
    entity_name = None
    
    if photo.content_type and photo.object_id:
        entity = photo.content_object
        entity_type = photo.content_type.model
        entity_id = str(photo.object_id)
        entity_name = getattr(entity, 'name', str(entity)) if entity else None
    
    # Generate variant URLs
    cloudflare_service = photo_service.cloudflare
    thumbnail_url = cloudflare_service.get_image_url(photo.cloudflare_image_id, 'thumbnail')
    banner_url = cloudflare_service.get_image_url(photo.cloudflare_image_id, 'banner')
    
    return {
        'id': photo.id,
        'cloudflare_image_id': photo.cloudflare_image_id,
        'cloudflare_url': photo.cloudflare_url,
        'title': photo.title,
        'description': photo.description,
        'credit': photo.credit,
        'photo_type': photo.photo_type,
        'is_visible': photo.is_visible,
        'uploaded_by_id': photo.uploaded_by_id,
        'uploaded_by_email': photo.uploaded_by.email if photo.uploaded_by else None,
        'moderation_status': photo.moderation_status,
        'moderated_by_id': photo.moderated_by_id,
        'moderated_by_email': photo.moderated_by.email if photo.moderated_by else None,
        'moderated_at': photo.moderated_at,
        'moderation_notes': photo.moderation_notes,
        'entity_type': entity_type,
        'entity_id': entity_id,
        'entity_name': entity_name,
        'width': photo.width,
        'height': photo.height,
        'file_size': photo.file_size,
        'mime_type': photo.mime_type,
        'display_order': photo.display_order,
        'thumbnail_url': thumbnail_url,
        'banner_url': banner_url,
        'created': photo.created_at,
        'modified': photo.modified_at,
    }


def get_entity_by_type(entity_type: str, entity_id: UUID):
    """
    Get entity instance by type and ID.
    
    Args:
        entity_type: Entity type (park, ride, company, ridemodel)
        entity_id: Entity UUID
        
    Returns:
        Entity instance
        
    Raises:
        ValueError: If entity type is invalid or not found
    """
    entity_map = {
        'park': Park,
        'ride': Ride,
        'company': Company,
        'ridemodel': RideModel,
    }
    
    model = entity_map.get(entity_type.lower())
    if not model:
        raise ValueError(f"Invalid entity type: {entity_type}")
    
    try:
        return model.objects.get(id=entity_id)
    except model.DoesNotExist:
        raise ValueError(f"{entity_type} with ID {entity_id} not found")


# ============================================================================
# Public Endpoints
# ============================================================================

@router.get("/photos", response=List[PhotoOut], auth=None)
@paginate
def list_photos(
    request: HttpRequest,
    status: Optional[str] = None,
    photo_type: Optional[str] = None,
    entity_type: Optional[str] = None,
    entity_id: Optional[UUID] = None,
):
    """
    List approved photos (public endpoint).
    
    Query Parameters:
        - status: Filter by moderation status (defaults to 'approved')
        - photo_type: Filter by photo type
        - entity_type: Filter by entity type
        - entity_id: Filter by entity ID
    """
    queryset = Photo.objects.select_related(
        'uploaded_by', 'moderated_by', 'content_type'
    )
    
    # Default to approved photos for public
    if status:
        queryset = queryset.filter(moderation_status=status)
    else:
        queryset = queryset.approved()
    
    if photo_type:
        queryset = queryset.filter(photo_type=photo_type)
    
    if entity_type and entity_id:
        try:
            entity = get_entity_by_type(entity_type, entity_id)
            content_type = ContentType.objects.get_for_model(entity)
            queryset = queryset.filter(
                content_type=content_type,
                object_id=entity_id
            )
        except ValueError as e:
            return []
    
    queryset = queryset.filter(is_visible=True).order_by('display_order', '-created_at')
    
    return queryset


@router.get("/photos/{photo_id}", response=PhotoOut, auth=None)
def get_photo(request: HttpRequest, photo_id: UUID):
    """
    Get photo details by ID (public endpoint).
    
    Only returns approved photos for non-authenticated users.
    """
    try:
        photo = Photo.objects.select_related(
            'uploaded_by', 'moderated_by', 'content_type'
        ).get(id=photo_id)
        
        # Only show approved photos to public
        if not request.auth and photo.moderation_status != 'approved':
            return 404, {"detail": "Photo not found"}
        
        return serialize_photo(photo)
    except Photo.DoesNotExist:
        return 404, {"detail": "Photo not found"}


@router.get("/{entity_type}/{entity_id}/photos", response=List[PhotoOut], auth=None)
def get_entity_photos(
    request: HttpRequest,
    entity_type: str,
    entity_id: UUID,
    photo_type: Optional[str] = None,
):
    """
    Get photos for a specific entity (public endpoint).
    
    Path Parameters:
        - entity_type: Entity type (park, ride, company, ridemodel)
        - entity_id: Entity UUID
        
    Query Parameters:
        - photo_type: Filter by photo type
    """
    try:
        entity = get_entity_by_type(entity_type, entity_id)
        photos = photo_service.get_entity_photos(
            entity,
            photo_type=photo_type,
            approved_only=not request.auth
        )
        return [serialize_photo(photo) for photo in photos]
    except ValueError as e:
        return 404, {"detail": str(e)}


# ============================================================================
# Authenticated Endpoints
# ============================================================================

@router.post("/photos/upload", response=PhotoUploadResponse, auth=jwt_auth)
def upload_photo(
    request: HttpRequest,
    file: UploadedFile = File(...),
    title: Optional[str] = Form(None),
    description: Optional[str] = Form(None),
    credit: Optional[str] = Form(None),
    photo_type: str = Form('gallery'),
    entity_type: Optional[str] = Form(None),
    entity_id: Optional[str] = Form(None),
):
    """
    Upload a new photo.
    
    Requires authentication. Photo enters moderation queue.
    
    Form Data:
        - file: Image file (required)
        - title: Photo title
        - description: Photo description
        - credit: Photo credit/attribution
        - photo_type: Type of photo (main, gallery, banner, logo, thumbnail, other)
        - entity_type: Entity type to attach to (optional)
        - entity_id: Entity ID to attach to (optional)
    """
    user = request.auth
    
    try:
        # Validate image
        validate_image(file, photo_type)
        
        # Get entity if provided
        entity = None
        if entity_type and entity_id:
            try:
                entity = get_entity_by_type(entity_type, UUID(entity_id))
            except (ValueError, TypeError) as e:
                return 400, {"detail": f"Invalid entity: {str(e)}"}
        
        # Create photo
        photo = photo_service.create_photo(
            file=file,
            user=user,
            entity=entity,
            photo_type=photo_type,
            title=title or file.name,
            description=description or '',
            credit=credit or '',
            is_visible=True,
        )
        
        return {
            'success': True,
            'message': 'Photo uploaded successfully and pending moderation',
            'photo': serialize_photo(photo),
        }
        
    except DjangoValidationError as e:
        return 400, {"detail": str(e)}
    except CloudFlareError as e:
        logger.error(f"CloudFlare upload failed: {str(e)}")
        return 500, {"detail": "Failed to upload image"}
    except Exception as e:
        logger.error(f"Photo upload failed: {str(e)}")
        return 500, {"detail": "An error occurred during upload"}


@router.patch("/photos/{photo_id}", response=PhotoOut, auth=jwt_auth)
def update_photo(
    request: HttpRequest,
    photo_id: UUID,
    payload: PhotoUpdate,
):
    """
    Update photo metadata.
    
    Users can only update their own photos.
    Moderators can update any photo.
    """
    user = request.auth
    
    try:
        photo = Photo.objects.get(id=photo_id)
        
        # Check permissions
        if photo.uploaded_by_id != user.id and not user.is_moderator:
            return 403, {"detail": "Permission denied"}
        
        # Update fields
        update_fields = []
        if payload.title is not None:
            photo.title = payload.title
            update_fields.append('title')
        if payload.description is not None:
            photo.description = payload.description
            update_fields.append('description')
        if payload.credit is not None:
            photo.credit = payload.credit
            update_fields.append('credit')
        if payload.photo_type is not None:
            photo.photo_type = payload.photo_type
            update_fields.append('photo_type')
        if payload.is_visible is not None:
            photo.is_visible = payload.is_visible
            update_fields.append('is_visible')
        if payload.display_order is not None:
            photo.display_order = payload.display_order
            update_fields.append('display_order')
        
        if update_fields:
            photo.save(update_fields=update_fields)
            logger.info(f"Photo {photo_id} updated by user {user.id}")
        
        return serialize_photo(photo)
        
    except Photo.DoesNotExist:
        return 404, {"detail": "Photo not found"}


@router.delete("/photos/{photo_id}", response=MessageSchema, auth=jwt_auth)
def delete_photo(request: HttpRequest, photo_id: UUID):
    """
    Delete own photo.
    
    Users can only delete their own photos.
    Photos are soft-deleted and removed from CloudFlare.
    """
    user = request.auth
    
    try:
        photo = Photo.objects.get(id=photo_id)
        
        # Check permissions
        if photo.uploaded_by_id != user.id and not user.is_moderator:
            return 403, {"detail": "Permission denied"}
        
        photo_service.delete_photo(photo)
        
        return {
            'success': True,
            'message': 'Photo deleted successfully',
        }
        
    except Photo.DoesNotExist:
        return 404, {"detail": "Photo not found"}


@router.post("/{entity_type}/{entity_id}/photos", response=MessageSchema, auth=jwt_auth)
def attach_photo_to_entity(
    request: HttpRequest,
    entity_type: str,
    entity_id: UUID,
    payload: PhotoAttachRequest,
):
    """
    Attach an existing photo to an entity.
    
    Requires authentication.
    """
    user = request.auth
    
    try:
        # Get entity
        entity = get_entity_by_type(entity_type, entity_id)
        
        # Get photo
        photo = Photo.objects.get(id=payload.photo_id)
        
        # Check permissions (can only attach own photos unless moderator)
        if photo.uploaded_by_id != user.id and not user.is_moderator:
            return 403, {"detail": "Permission denied"}
        
        # Attach photo
        photo_service.attach_to_entity(photo, entity)
        
        # Update photo type if provided
        if payload.photo_type:
            photo.photo_type = payload.photo_type
            photo.save(update_fields=['photo_type'])
        
        return {
            'success': True,
            'message': f'Photo attached to {entity_type} successfully',
        }
        
    except ValueError as e:
        return 400, {"detail": str(e)}
    except Photo.DoesNotExist:
        return 404, {"detail": "Photo not found"}


# ============================================================================
# Moderator Endpoints
# ============================================================================

@router.get("/photos/pending", response=List[PhotoOut], auth=require_moderator)
@paginate
def list_pending_photos(request: HttpRequest):
    """
    List photos pending moderation (moderators only).
    """
    queryset = Photo.objects.select_related(
        'uploaded_by', 'moderated_by', 'content_type'
    ).pending().order_by('-created_at')
    
    return queryset


@router.post("/photos/{photo_id}/approve", response=PhotoOut, auth=require_moderator)
def approve_photo(request: HttpRequest, photo_id: UUID):
    """
    Approve a photo (moderators only).
    """
    user = request.auth
    
    try:
        photo = Photo.objects.get(id=photo_id)
        photo = photo_service.moderate_photo(
            photo=photo,
            status='approved',
            moderator=user,
        )
        
        return serialize_photo(photo)
        
    except Photo.DoesNotExist:
        return 404, {"detail": "Photo not found"}


@router.post("/photos/{photo_id}/reject", response=PhotoOut, auth=require_moderator)
def reject_photo(
    request: HttpRequest,
    photo_id: UUID,
    payload: PhotoModerateRequest,
):
    """
    Reject a photo (moderators only).
    """
    user = request.auth
    
    try:
        photo = Photo.objects.get(id=photo_id)
        photo = photo_service.moderate_photo(
            photo=photo,
            status='rejected',
            moderator=user,
            notes=payload.notes or '',
        )
        
        return serialize_photo(photo)
        
    except Photo.DoesNotExist:
        return 404, {"detail": "Photo not found"}


@router.post("/photos/{photo_id}/flag", response=PhotoOut, auth=require_moderator)
def flag_photo(
    request: HttpRequest,
    photo_id: UUID,
    payload: PhotoModerateRequest,
):
    """
    Flag a photo for review (moderators only).
    """
    user = request.auth
    
    try:
        photo = Photo.objects.get(id=photo_id)
        photo = photo_service.moderate_photo(
            photo=photo,
            status='flagged',
            moderator=user,
            notes=payload.notes or '',
        )
        
        return serialize_photo(photo)
        
    except Photo.DoesNotExist:
        return 404, {"detail": "Photo not found"}


@router.get("/photos/stats", response=PhotoStatsOut, auth=require_moderator)
def get_photo_stats(request: HttpRequest):
    """
    Get photo statistics (moderators only).
    """
    stats = Photo.objects.aggregate(
        total=Count('id'),
        pending=Count('id', filter=Q(moderation_status='pending')),
        approved=Count('id', filter=Q(moderation_status='approved')),
        rejected=Count('id', filter=Q(moderation_status='rejected')),
        flagged=Count('id', filter=Q(moderation_status='flagged')),
        total_size=Sum('file_size'),
    )
    
    return {
        'total_photos': stats['total'] or 0,
        'pending_photos': stats['pending'] or 0,
        'approved_photos': stats['approved'] or 0,
        'rejected_photos': stats['rejected'] or 0,
        'flagged_photos': stats['flagged'] or 0,
        'total_size_mb': round((stats['total_size'] or 0) / (1024 * 1024), 2),
    }


# ============================================================================
# Admin Endpoints
# ============================================================================

@router.delete("/photos/{photo_id}/admin", response=MessageSchema, auth=require_admin)
def admin_delete_photo(request: HttpRequest, photo_id: UUID):
    """
    Force delete any photo (admins only).
    
    Permanently removes photo from database and CloudFlare.
    """
    try:
        photo = Photo.objects.get(id=photo_id)
        photo_service.delete_photo(photo, delete_from_cloudflare=True)
        
        logger.info(f"Photo {photo_id} force deleted by admin {request.auth.id}")
        
        return {
            'success': True,
            'message': 'Photo permanently deleted',
        }
        
    except Photo.DoesNotExist:
        return 404, {"detail": "Photo not found"}


@router.post(
    "/{entity_type}/{entity_id}/photos/reorder",
    response=MessageSchema,
    auth=require_admin
)
def reorder_entity_photos(
    request: HttpRequest,
    entity_type: str,
    entity_id: UUID,
    payload: PhotoReorderRequest,
):
    """
    Reorder photos for an entity (admins only).
    """
    try:
        entity = get_entity_by_type(entity_type, entity_id)
        
        photo_service.reorder_photos(
            entity=entity,
            photo_ids=payload.photo_ids,
            photo_type=payload.photo_type,
        )
        
        return {
            'success': True,
            'message': 'Photos reordered successfully',
        }
        
    except ValueError as e:
        return 400, {"detail": str(e)}
