"""
Moderation API endpoints.

Provides REST API for content submission and moderation workflow.
"""
from typing import List, Optional
from uuid import UUID
from ninja import Router
from django.shortcuts import get_object_or_404
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError, PermissionDenied

from apps.moderation.models import ContentSubmission, SubmissionItem
from apps.moderation.services import ModerationService
from api.v1.schemas import (
    ContentSubmissionCreate,
    ContentSubmissionOut,
    ContentSubmissionDetail,
    SubmissionListOut,
    StartReviewRequest,
    ApproveRequest,
    ApproveSelectiveRequest,
    RejectRequest,
    RejectSelectiveRequest,
    ApprovalResponse,
    SelectiveApprovalResponse,
    SelectiveRejectionResponse,
    ErrorResponse,
)

router = Router(tags=['Moderation'])


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

def _submission_to_dict(submission: ContentSubmission) -> dict:
    """Convert submission model to dict for schema."""
    return {
        'id': submission.id,
        'status': submission.status,
        'submission_type': submission.submission_type,
        'title': submission.title,
        'description': submission.description or '',
        'entity_type': submission.entity_type.model,
        'entity_id': submission.entity_id,
        'user_id': submission.user.id,
        'user_email': submission.user.email,
        'locked_by_id': submission.locked_by.id if submission.locked_by else None,
        'locked_by_email': submission.locked_by.email if submission.locked_by else None,
        'locked_at': submission.locked_at,
        'reviewed_by_id': submission.reviewed_by.id if submission.reviewed_by else None,
        'reviewed_by_email': submission.reviewed_by.email if submission.reviewed_by else None,
        'reviewed_at': submission.reviewed_at,
        'rejection_reason': submission.rejection_reason or '',
        'source': submission.source,
        'metadata': submission.metadata,
        'items_count': submission.get_items_count(),
        'approved_items_count': submission.get_approved_items_count(),
        'rejected_items_count': submission.get_rejected_items_count(),
        'created': submission.created,
        'modified': submission.modified,
    }


def _item_to_dict(item: SubmissionItem) -> dict:
    """Convert submission item model to dict for schema."""
    return {
        'id': item.id,
        'submission_id': item.submission.id,
        'field_name': item.field_name,
        'field_label': item.field_label or item.field_name,
        'old_value': item.old_value,
        'new_value': item.new_value,
        'change_type': item.change_type,
        'is_required': item.is_required,
        'order': item.order,
        'status': item.status,
        'reviewed_by_id': item.reviewed_by.id if item.reviewed_by else None,
        'reviewed_by_email': item.reviewed_by.email if item.reviewed_by else None,
        'reviewed_at': item.reviewed_at,
        'rejection_reason': item.rejection_reason or '',
        'old_value_display': item.old_value_display,
        'new_value_display': item.new_value_display,
        'created': item.created,
        'modified': item.modified,
    }


def _get_entity(entity_type: str, entity_id: UUID):
    """Get entity instance from type string and ID."""
    # Map entity type strings to models
    type_map = {
        'park': 'entities.Park',
        'ride': 'entities.Ride',
        'company': 'entities.Company',
        'ridemodel': 'entities.RideModel',
    }
    
    app_label, model = type_map.get(entity_type.lower(), '').split('.')
    content_type = ContentType.objects.get(app_label=app_label, model=model.lower())
    model_class = content_type.model_class()
    
    return get_object_or_404(model_class, id=entity_id)


# ============================================================================
# Submission Endpoints
# ============================================================================

@router.post('/submissions', response={201: ContentSubmissionOut, 400: ErrorResponse, 401: ErrorResponse})
def create_submission(request, data: ContentSubmissionCreate):
    """
    Create a new content submission.
    
    Creates a submission with multiple items representing field changes.
    If auto_submit is True, the submission is immediately moved to pending state.
    """
    # TODO: Require authentication
    # For now, use a test user or get from request
    from apps.users.models import User
    user = User.objects.first()  # TEMP: Get first user for testing
    
    if not user:
        return 401, {'detail': 'Authentication required'}
    
    try:
        # Get entity
        entity = _get_entity(data.entity_type, data.entity_id)
        
        # Prepare items data
        items_data = [
            {
                'field_name': item.field_name,
                'field_label': item.field_label,
                'old_value': item.old_value,
                'new_value': item.new_value,
                'change_type': item.change_type,
                'is_required': item.is_required,
                'order': item.order,
            }
            for item in data.items
        ]
        
        # Create submission
        submission = ModerationService.create_submission(
            user=user,
            entity=entity,
            submission_type=data.submission_type,
            title=data.title,
            description=data.description or '',
            items_data=items_data,
            metadata=data.metadata,
            auto_submit=data.auto_submit,
            source='api'
        )
        
        return 201, _submission_to_dict(submission)
        
    except Exception as e:
        return 400, {'detail': str(e)}


@router.get('/submissions', response=SubmissionListOut)
def list_submissions(
    request,
    status: Optional[str] = None,
    page: int = 1,
    page_size: int = 50
):
    """
    List content submissions with optional filtering.
    
    Query Parameters:
    - status: Filter by status (draft, pending, reviewing, approved, rejected)
    - page: Page number (default: 1)
    - page_size: Items per page (default: 50, max: 100)
    """
    # Validate page_size
    page_size = min(page_size, 100)
    offset = (page - 1) * page_size
    
    # Get submissions
    submissions = ModerationService.get_queue(
        status=status,
        limit=page_size,
        offset=offset
    )
    
    # Get total count
    total_queryset = ContentSubmission.objects.all()
    if status:
        total_queryset = total_queryset.filter(status=status)
    total = total_queryset.count()
    
    # Calculate total pages
    total_pages = (total + page_size - 1) // page_size
    
    # Convert to dicts
    items = [_submission_to_dict(sub) for sub in submissions]
    
    return {
        'items': items,
        'total': total,
        'page': page,
        'page_size': page_size,
        'total_pages': total_pages,
    }


@router.get('/submissions/{submission_id}', response={200: ContentSubmissionDetail, 404: ErrorResponse})
def get_submission(request, submission_id: UUID):
    """
    Get detailed submission information with all items.
    """
    try:
        submission = ModerationService.get_submission_details(submission_id)
        
        # Convert to dict with items
        data = _submission_to_dict(submission)
        data['items'] = [_item_to_dict(item) for item in submission.items.all()]
        
        return 200, data
        
    except ContentSubmission.DoesNotExist:
        return 404, {'detail': 'Submission not found'}


@router.delete('/submissions/{submission_id}', response={204: None, 403: ErrorResponse, 404: ErrorResponse})
def delete_submission(request, submission_id: UUID):
    """
    Delete a submission (only if draft/pending and owned by user).
    """
    # TODO: Get current user from request
    from apps.users.models import User
    user = User.objects.first()  # TEMP
    
    try:
        ModerationService.delete_submission(submission_id, user)
        return 204, None
        
    except ContentSubmission.DoesNotExist:
        return 404, {'detail': 'Submission not found'}
    except PermissionDenied as e:
        return 403, {'detail': str(e)}
    except ValidationError as e:
        return 400, {'detail': str(e)}


# ============================================================================
# Review Endpoints
# ============================================================================

@router.post(
    '/submissions/{submission_id}/start-review',
    response={200: ContentSubmissionOut, 400: ErrorResponse, 403: ErrorResponse, 404: ErrorResponse}
)
def start_review(request, submission_id: UUID, data: StartReviewRequest):
    """
    Start reviewing a submission (lock it for 15 minutes).
    
    Only moderators can start reviews.
    """
    # TODO: Get current user (moderator) from request
    from apps.users.models import User
    user = User.objects.first()  # TEMP
    
    try:
        submission = ModerationService.start_review(submission_id, user)
        return 200, _submission_to_dict(submission)
        
    except ContentSubmission.DoesNotExist:
        return 404, {'detail': 'Submission not found'}
    except PermissionDenied as e:
        return 403, {'detail': str(e)}
    except ValidationError as e:
        return 400, {'detail': str(e)}


@router.post(
    '/submissions/{submission_id}/approve',
    response={200: ApprovalResponse, 400: ErrorResponse, 403: ErrorResponse, 404: ErrorResponse}
)
def approve_submission(request, submission_id: UUID, data: ApproveRequest):
    """
    Approve an entire submission and apply all changes.
    
    Uses atomic transactions - all changes are applied or none are.
    Only moderators can approve submissions.
    """
    # TODO: Get current user (moderator) from request
    from apps.users.models import User
    user = User.objects.first()  # TEMP
    
    try:
        submission = ModerationService.approve_submission(submission_id, user)
        
        return 200, {
            'success': True,
            'message': 'Submission approved successfully',
            'submission': _submission_to_dict(submission)
        }
        
    except ContentSubmission.DoesNotExist:
        return 404, {'detail': 'Submission not found'}
    except PermissionDenied as e:
        return 403, {'detail': str(e)}
    except ValidationError as e:
        return 400, {'detail': str(e)}


@router.post(
    '/submissions/{submission_id}/approve-selective',
    response={200: SelectiveApprovalResponse, 400: ErrorResponse, 403: ErrorResponse, 404: ErrorResponse}
)
def approve_selective(request, submission_id: UUID, data: ApproveSelectiveRequest):
    """
    Approve only specific items in a submission.
    
    Allows moderators to approve some changes while leaving others pending or rejected.
    Uses atomic transactions for data integrity.
    """
    # TODO: Get current user (moderator) from request
    from apps.users.models import User
    user = User.objects.first()  # TEMP
    
    try:
        result = ModerationService.approve_selective(
            submission_id,
            user,
            [str(item_id) for item_id in data.item_ids]
        )
        
        return 200, {
            'success': True,
            'message': f"Approved {result['approved']} of {result['total']} items",
            **result
        }
        
    except ContentSubmission.DoesNotExist:
        return 404, {'detail': 'Submission not found'}
    except PermissionDenied as e:
        return 403, {'detail': str(e)}
    except ValidationError as e:
        return 400, {'detail': str(e)}


@router.post(
    '/submissions/{submission_id}/reject',
    response={200: ApprovalResponse, 400: ErrorResponse, 403: ErrorResponse, 404: ErrorResponse}
)
def reject_submission(request, submission_id: UUID, data: RejectRequest):
    """
    Reject an entire submission.
    
    All pending items are rejected with the provided reason.
    Only moderators can reject submissions.
    """
    # TODO: Get current user (moderator) from request
    from apps.users.models import User
    user = User.objects.first()  # TEMP
    
    try:
        submission = ModerationService.reject_submission(submission_id, user, data.reason)
        
        return 200, {
            'success': True,
            'message': 'Submission rejected',
            'submission': _submission_to_dict(submission)
        }
        
    except ContentSubmission.DoesNotExist:
        return 404, {'detail': 'Submission not found'}
    except PermissionDenied as e:
        return 403, {'detail': str(e)}
    except ValidationError as e:
        return 400, {'detail': str(e)}


@router.post(
    '/submissions/{submission_id}/reject-selective',
    response={200: SelectiveRejectionResponse, 400: ErrorResponse, 403: ErrorResponse, 404: ErrorResponse}
)
def reject_selective(request, submission_id: UUID, data: RejectSelectiveRequest):
    """
    Reject only specific items in a submission.
    
    Allows moderators to reject some changes while leaving others pending or approved.
    """
    # TODO: Get current user (moderator) from request
    from apps.users.models import User
    user = User.objects.first()  # TEMP
    
    try:
        result = ModerationService.reject_selective(
            submission_id,
            user,
            [str(item_id) for item_id in data.item_ids],
            data.reason or ''
        )
        
        return 200, {
            'success': True,
            'message': f"Rejected {result['rejected']} of {result['total']} items",
            **result
        }
        
    except ContentSubmission.DoesNotExist:
        return 404, {'detail': 'Submission not found'}
    except PermissionDenied as e:
        return 403, {'detail': str(e)}
    except ValidationError as e:
        return 400, {'detail': str(e)}


@router.post(
    '/submissions/{submission_id}/unlock',
    response={200: ContentSubmissionOut, 404: ErrorResponse}
)
def unlock_submission(request, submission_id: UUID):
    """
    Manually unlock a submission.
    
    Removes the review lock. Can be used by moderators or automatically by cleanup tasks.
    """
    try:
        submission = ModerationService.unlock_submission(submission_id)
        return 200, _submission_to_dict(submission)
        
    except ContentSubmission.DoesNotExist:
        return 404, {'detail': 'Submission not found'}


# ============================================================================
# Queue Endpoints
# ============================================================================

@router.get('/queue/pending', response=SubmissionListOut)
def get_pending_queue(request, page: int = 1, page_size: int = 50):
    """
    Get pending submissions queue.
    
    Returns all submissions awaiting review.
    """
    return list_submissions(request, status='pending', page=page, page_size=page_size)


@router.get('/queue/reviewing', response=SubmissionListOut)
def get_reviewing_queue(request, page: int = 1, page_size: int = 50):
    """
    Get submissions currently under review.
    
    Returns all submissions being reviewed by moderators.
    """
    return list_submissions(request, status='reviewing', page=page, page_size=page_size)


@router.get('/queue/my-submissions', response=SubmissionListOut)
def get_my_submissions(request, page: int = 1, page_size: int = 50):
    """
    Get current user's submissions.
    
    Returns all submissions created by the authenticated user.
    """
    # TODO: Get current user from request
    from apps.users.models import User
    user = User.objects.first()  # TEMP
    
    # Validate page_size
    page_size = min(page_size, 100)
    offset = (page - 1) * page_size
    
    # Get user's submissions
    submissions = ModerationService.get_queue(
        user=user,
        limit=page_size,
        offset=offset
    )
    
    # Get total count
    total = ContentSubmission.objects.filter(user=user).count()
    
    # Calculate total pages
    total_pages = (total + page_size - 1) // page_size
    
    # Convert to dicts
    items = [_submission_to_dict(sub) for sub in submissions]
    
    return {
        'items': items,
        'total': total,
        'page': page,
        'page_size': page_size,
        'total_pages': total_pages,
    }
