from rest_framework import viewsets, filters, status
from rest_framework.decorators import action
from rest_framework.response import Response
from django_filters.rest_framework import DjangoFilterBackend
from django.db import transaction
from igny8_core.api.base import SiteSectorModelViewSet
from igny8_core.api.pagination import CustomPageNumberPagination
from .models import Tasks, Images, Content
from .serializers import TasksSerializer, ImagesSerializer, ContentSerializer


class TasksViewSet(SiteSectorModelViewSet):
    """
    ViewSet for managing tasks with CRUD operations
    """
    queryset = Tasks.objects.all()
    serializer_class = TasksSerializer
    pagination_class = CustomPageNumberPagination  # Explicitly use custom pagination
    
    # DRF filtering configuration
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    
    # Search configuration
    search_fields = ['title', 'keywords']
    
    # Ordering configuration
    ordering_fields = ['title', 'created_at', 'word_count', 'status']
    ordering = ['-created_at']  # Default ordering (newest first)
    
    # Filter configuration
    filterset_fields = ['status', 'cluster_id', 'content_type', 'content_structure']
    
    def perform_create(self, serializer):
        """Require explicit site_id and sector_id - no defaults."""
        user = getattr(self.request, 'user', None)
        
        try:
            query_params = getattr(self.request, 'query_params', None)
            if query_params is None:
                query_params = getattr(self.request, 'GET', {})
        except AttributeError:
            query_params = {}
        
        site_id = serializer.validated_data.get('site_id') or query_params.get('site_id')
        sector_id = serializer.validated_data.get('sector_id') or query_params.get('sector_id')
        
        from igny8_core.auth.models import Site, Sector
        from rest_framework.exceptions import ValidationError
        
        # Site ID is REQUIRED
        if not site_id:
            raise ValidationError("site_id is required. Please select a site.")
        
        try:
            site = Site.objects.get(id=site_id)
        except Site.DoesNotExist:
            raise ValidationError(f"Site with id {site_id} does not exist")
        
        # Sector ID is REQUIRED
        if not sector_id:
            raise ValidationError("sector_id is required. Please select a sector.")
        
        try:
            sector = Sector.objects.get(id=sector_id)
            if sector.site_id != site_id:
                raise ValidationError(f"Sector does not belong to the selected site")
        except Sector.DoesNotExist:
            raise ValidationError(f"Sector with id {sector_id} does not exist")
        
        serializer.validated_data.pop('site_id', None)
        serializer.validated_data.pop('sector_id', None)
        
        account = getattr(self.request, 'account', None)
        if not account and user and user.is_authenticated and user.account:
            account = user.account
        if not account:
            account = site.account
        
        serializer.save(account=account, site=site, sector=sector)
    
    @action(detail=False, methods=['post'], url_path='bulk_delete', url_name='bulk_delete')
    def bulk_delete(self, request):
        """Bulk delete tasks"""
        ids = request.data.get('ids', [])
        if not ids:
            return Response({'error': 'No IDs provided'}, status=status.HTTP_400_BAD_REQUEST)
        
        queryset = self.get_queryset()
        deleted_count, _ = queryset.filter(id__in=ids).delete()
        
        return Response({'deleted_count': deleted_count}, status=status.HTTP_200_OK)
    
    @action(detail=False, methods=['post'], url_path='bulk_update', url_name='bulk_update')
    def bulk_update(self, request):
        """Bulk update task status"""
        ids = request.data.get('ids', [])
        status_value = request.data.get('status')
        
        if not ids:
            return Response({'error': 'No IDs provided'}, status=status.HTTP_400_BAD_REQUEST)
        if not status_value:
            return Response({'error': 'No status provided'}, status=status.HTTP_400_BAD_REQUEST)
        
        queryset = self.get_queryset()
        updated_count = queryset.filter(id__in=ids).update(status=status_value)
        
        return Response({'updated_count': updated_count}, status=status.HTTP_200_OK)
    
    @action(detail=False, methods=['post'], url_path='auto_generate_content', url_name='auto_generate_content')
    def auto_generate_content(self, request):
        """Auto-generate content for tasks using AI"""
        import logging
        from django.db import OperationalError, DatabaseError, IntegrityError
        from django.core.exceptions import ValidationError
        
        logger = logging.getLogger(__name__)
        
        try:
            ids = request.data.get('ids', [])
            if not ids:
                logger.warning("auto_generate_content: No IDs provided")
                return Response({
                    'error': 'No IDs provided',
                    'type': 'ValidationError'
                }, status=status.HTTP_400_BAD_REQUEST)
            
            if len(ids) > 10:
                logger.warning(f"auto_generate_content: Too many IDs provided: {len(ids)}")
                return Response({
                    'error': 'Maximum 10 tasks allowed for content generation',
                    'type': 'ValidationError'
                }, status=status.HTTP_400_BAD_REQUEST)
            
            logger.info(f"auto_generate_content: Processing {len(ids)} task IDs: {ids}")
            
            # Get account
            account = getattr(request, 'account', None)
            account_id = account.id if account else None
            logger.info(f"auto_generate_content: Account ID: {account_id}")
            
            # Validate task IDs exist in database before proceeding
            try:
                queryset = self.get_queryset()
                existing_tasks = queryset.filter(id__in=ids)
                existing_count = existing_tasks.count()
                existing_ids = list(existing_tasks.values_list('id', flat=True))
                
                logger.info(f"auto_generate_content: Found {existing_count} existing tasks out of {len(ids)} requested")
                logger.info(f"auto_generate_content: Existing task IDs: {existing_ids}")
                
                if existing_count == 0:
                    logger.error(f"auto_generate_content: No tasks found for IDs: {ids}")
                    return Response({
                        'error': f'No tasks found for the provided IDs: {ids}',
                        'type': 'NotFound',
                        'requested_ids': ids
                    }, status=status.HTTP_404_NOT_FOUND)
                
                if existing_count < len(ids):
                    missing_ids = set(ids) - set(existing_ids)
                    logger.warning(f"auto_generate_content: Some task IDs not found: {missing_ids}")
                    # Continue with existing tasks, but log warning
                
            except (OperationalError, DatabaseError) as db_error:
                logger.error("=" * 80)
                logger.error("DATABASE ERROR: Failed to query tasks")
                logger.error(f"  - Error type: {type(db_error).__name__}")
                logger.error(f"  - Error message: {str(db_error)}")
                logger.error(f"  - Requested IDs: {ids}")
                logger.error(f"  - Account ID: {account_id}")
                logger.error("=" * 80, exc_info=True)
                
                return Response({
                    'error': f'Database error while querying tasks: {str(db_error)}',
                    'type': 'OperationalError',
                    'details': 'Failed to retrieve tasks from database. Please check database connection and try again.'
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            
            # Try to queue Celery task, fall back to synchronous if Celery not available
            try:
                from .tasks import auto_generate_content_task
                
                if hasattr(auto_generate_content_task, 'delay'):
                    # Celery is available - queue async task
                    logger.info(f"auto_generate_content: Queuing Celery task for {len(ids)} tasks")
                    try:
                        task = auto_generate_content_task.delay(ids, account_id=account_id)
                        logger.info(f"auto_generate_content: Celery task queued successfully: {task.id}")
                        return Response({
                            'success': True,
                            'task_id': str(task.id),
                            'message': 'Content generation started'
                        }, status=status.HTTP_200_OK)
                    except Exception as celery_error:
                        logger.error("=" * 80)
                        logger.error("CELERY ERROR: Failed to queue task")
                        logger.error(f"  - Error type: {type(celery_error).__name__}")
                        logger.error(f"  - Error message: {str(celery_error)}")
                        logger.error(f"  - Task IDs: {ids}")
                        logger.error(f"  - Account ID: {account_id}")
                        logger.error("=" * 80, exc_info=True)
                        
                        # Fall back to synchronous execution
                        logger.info("auto_generate_content: Falling back to synchronous execution")
                        result = auto_generate_content_task(ids, account_id=account_id)
                        if result.get('success'):
                            return Response({
                                'success': True,
                                'tasks_updated': result.get('tasks_updated', 0),
                                'message': 'Content generated successfully (synchronous)'
                            }, status=status.HTTP_200_OK)
                        else:
                            return Response({
                                'error': result.get('error', 'Content generation failed'),
                                'type': 'TaskExecutionError'
                            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                else:
                    # Celery not available - execute synchronously
                    logger.info(f"auto_generate_content: Executing synchronously (Celery not available)")
                    result = auto_generate_content_task(ids, account_id=account_id)
                    if result.get('success'):
                        logger.info(f"auto_generate_content: Synchronous execution successful: {result.get('tasks_updated', 0)} tasks updated")
                        return Response({
                            'success': True,
                            'tasks_updated': result.get('tasks_updated', 0),
                            'message': 'Content generated successfully'
                        }, status=status.HTTP_200_OK)
                    else:
                        logger.error(f"auto_generate_content: Synchronous execution failed: {result.get('error', 'Unknown error')}")
                        return Response({
                            'error': result.get('error', 'Content generation failed'),
                            'type': 'TaskExecutionError'
                        }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                    
            except ImportError as import_error:
                logger.error(f"auto_generate_content: ImportError - tasks module not available: {str(import_error)}")
                # Tasks module not available - update status only
                try:
                    queryset = self.get_queryset()
                    tasks = queryset.filter(id__in=ids, status__in=['queued', 'in_progress'])
                    updated_count = tasks.update(status='draft', content='[AI content generation not available]')
                    
                    logger.info(f"auto_generate_content: Updated {updated_count} tasks (AI generation not available)")
                    return Response({
                        'updated_count': updated_count,
                        'message': 'Tasks updated (AI generation not available)'
                    }, status=status.HTTP_200_OK)
                except (OperationalError, DatabaseError) as db_error:
                    logger.error("=" * 80)
                    logger.error("DATABASE ERROR: Failed to update tasks")
                    logger.error(f"  - Error type: {type(db_error).__name__}")
                    logger.error(f"  - Error message: {str(db_error)}")
                    logger.error("=" * 80, exc_info=True)
                    return Response({
                        'error': f'Database error while updating tasks: {str(db_error)}',
                        'type': 'OperationalError',
                        'details': 'Failed to update tasks in database. Please check database connection.'
                    }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            
            except (OperationalError, DatabaseError) as db_error:
                logger.error("=" * 80)
                logger.error("DATABASE ERROR: Failed during task execution")
                logger.error(f"  - Error type: {type(db_error).__name__}")
                logger.error(f"  - Error message: {str(db_error)}")
                logger.error(f"  - Task IDs: {ids}")
                logger.error(f"  - Account ID: {account_id}")
                logger.error("=" * 80, exc_info=True)
                
                return Response({
                    'error': f'Database error during content generation: {str(db_error)}',
                    'type': 'OperationalError',
                    'details': 'A database operation failed. This may be due to connection issues, constraint violations, or data integrity problems. Check the logs for more details.'
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            
            except IntegrityError as integrity_error:
                logger.error("=" * 80)
                logger.error("INTEGRITY ERROR: Data integrity violation")
                logger.error(f"  - Error message: {str(integrity_error)}")
                logger.error(f"  - Task IDs: {ids}")
                logger.error("=" * 80, exc_info=True)
                
                return Response({
                    'error': f'Data integrity error: {str(integrity_error)}',
                    'type': 'IntegrityError',
                    'details': 'The operation violated database constraints. This may indicate missing required relationships or invalid data.'
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            
            except ValidationError as validation_error:
                logger.error(f"auto_generate_content: ValidationError: {str(validation_error)}")
                return Response({
                    'error': f'Validation error: {str(validation_error)}',
                    'type': 'ValidationError'
                }, status=status.HTTP_400_BAD_REQUEST)
            
            except Exception as e:
                logger.error("=" * 80)
                logger.error("UNEXPECTED ERROR in auto_generate_content")
                logger.error(f"  - Error type: {type(e).__name__}")
                logger.error(f"  - Error message: {str(e)}")
                logger.error(f"  - Task IDs: {ids}")
                logger.error(f"  - Account ID: {account_id}")
                logger.error("=" * 80, exc_info=True)
                
                return Response({
                    'error': f'Unexpected error: {str(e)}',
                    'type': type(e).__name__,
                    'details': 'An unexpected error occurred. Please check the logs for more details.'
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        
        except Exception as outer_error:
            logger.error("=" * 80)
            logger.error("CRITICAL ERROR: Outer exception handler")
            logger.error(f"  - Error type: {type(outer_error).__name__}")
            logger.error(f"  - Error message: {str(outer_error)}")
            logger.error("=" * 80, exc_info=True)
            
            return Response({
                'error': f'Critical error: {str(outer_error)}',
                'type': type(outer_error).__name__
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class ImagesViewSet(SiteSectorModelViewSet):
    """
    ViewSet for managing task images
    """
    queryset = Images.objects.all()
    serializer_class = ImagesSerializer
    
    filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
    ordering_fields = ['created_at', 'position']
    ordering = ['task', 'position', '-created_at']
    filterset_fields = ['task_id', 'image_type', 'status']
    
    def perform_create(self, serializer):
        """Override to automatically set account"""
        account = getattr(self.request, 'account', None)
        if account:
            serializer.save(account=account)
        else:
            serializer.save()
    
    @action(detail=False, methods=['post'], url_path='auto_generate', url_name='auto_generate_images')
    def auto_generate_images(self, request):
        """Auto-generate images for tasks using AI"""
        task_ids = request.data.get('task_ids', [])
        if not task_ids:
            return Response({'error': 'No task IDs provided'}, status=status.HTTP_400_BAD_REQUEST)
        
        if len(task_ids) > 10:
            return Response({'error': 'Maximum 10 tasks allowed for image generation'}, status=status.HTTP_400_BAD_REQUEST)
        
        # Get account
        account = getattr(request, 'account', None)
        account_id = account.id if account else None
        
        # Try to queue Celery task, fall back to synchronous if Celery not available
        try:
            from .tasks import auto_generate_images_task
            if hasattr(auto_generate_images_task, 'delay'):
                # Celery is available - queue async task
                task = auto_generate_images_task.delay(task_ids, account_id=account_id)
                return Response({
                    'success': True,
                    'task_id': str(task.id),
                    'message': 'Image generation started'
                }, status=status.HTTP_200_OK)
            else:
                # Celery not available - execute synchronously
                result = auto_generate_images_task(task_ids, account_id=account_id)
                if result.get('success'):
                    return Response({
                        'success': True,
                        'images_created': result.get('images_created', 0),
                        'message': result.get('message', 'Image generation completed')
                    }, status=status.HTTP_200_OK)
                else:
                    return Response({
                        'error': result.get('error', 'Image generation failed')
                    }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        except ImportError:
            # Tasks module not available
            return Response({
                'error': 'Image generation task not available'
            }, status=status.HTTP_503_SERVICE_UNAVAILABLE)


class ContentViewSet(SiteSectorModelViewSet):
    """
    ViewSet for managing task content
    """
    queryset = Content.objects.all()
    serializer_class = ContentSerializer
    
    filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
    ordering_fields = ['generated_at', 'updated_at']
    ordering = ['-generated_at']
    filterset_fields = ['task_id']
    
    def perform_create(self, serializer):
        """Override to automatically set account"""
        account = getattr(self.request, 'account', None)
        if account:
            serializer.save(account=account)
        else:
            serializer.save()

