"""
Integration settings views - for OpenAI, Runware, GSC integrations
"""
import logging
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response
from django.db import transaction
from igny8_core.api.base import AccountModelViewSet
from django.conf import settings

logger = logging.getLogger(__name__)


class IntegrationSettingsViewSet(viewsets.ViewSet):
    """
    ViewSet for managing integration settings (OpenAI, Runware, GSC)
    Following reference plugin pattern: WordPress uses update_option() for igny8_api_settings
    We store in IntegrationSettings model with account isolation
    """
    permission_classes = []  # Allow any for now
    
    def list(self, request):
        """List all integrations - for debugging URL patterns"""
        logger.info("[IntegrationSettingsViewSet] list() called")
        return Response({
            'message': 'IntegrationSettingsViewSet is working',
            'available_endpoints': [
                'GET /api/v1/system/settings/integrations/<pk>/',
                'POST /api/v1/system/settings/integrations/<pk>/save/',
                'POST /api/v1/system/settings/integrations/<pk>/test/',
                'POST /api/v1/system/settings/integrations/<pk>/generate/',
            ]
        })
    
    def retrieve(self, request, pk=None):
        """Get integration settings - GET /api/v1/system/settings/integrations/{pk}/"""
        return self.get_settings(request, pk)
    
    def update(self, request, pk=None):
        """Save integration settings (PUT) - PUT /api/v1/system/settings/integrations/{pk}/"""
        return self.save_settings(request, pk)
    
    def save_post(self, request, pk=None, **kwargs):
        """Save integration settings (POST) - POST /api/v1/system/settings/integrations/{pk}/save/
        This matches the frontend endpoint call exactly.
        Reference plugin: WordPress form submits to options.php which calls update_option() via register_setting callback.
        We save to IntegrationSettings model instead.
        """
        # Extract pk from kwargs if not passed as parameter (DRF passes via **kwargs)
        if not pk:
            pk = kwargs.get('pk')
        return self.save_settings(request, pk)
    
    @action(detail=True, methods=['post'], url_path='test', url_name='test')
    def test_connection(self, request, pk=None):
        """
        Test API connection for OpenAI or Runware
        Supports two modes:
        - with_response=false: Simple connection test (GET /v1/models)
        - with_response=true: Full response test with ping message
        """
        integration_type = pk  # 'openai', 'runware'
        
        logger.info(f"[test_connection] Called for integration_type={integration_type}, user={getattr(request, 'user', None)}, account={getattr(request, 'account', None)}")
        
        if not integration_type:
            return Response({'error': 'Integration type is required'}, status=status.HTTP_400_BAD_REQUEST)
        
        # Get API key and config from request or saved settings
        config = request.data.get('config', {}) if isinstance(request.data.get('config'), dict) else {}
        api_key = request.data.get('apiKey') or config.get('apiKey')
        
        # Merge request.data with config if config is a dict
        if not isinstance(config, dict):
            config = {}
        
        if not api_key:
            # Try to get from saved settings
            account = getattr(request, 'account', None)
            logger.info(f"[test_connection] Account from request: {account.id if account else None}")
            # Fallback to user's account
            if not account:
                user = getattr(request, 'user', None)
                if user and hasattr(user, 'is_authenticated') and user.is_authenticated:
                    account = getattr(user, 'account', None)
            # Fallback to default account
            if not account:
                from igny8_core.auth.models import Account
                try:
                    account = Account.objects.first()
                except Exception:
                    pass
            
            if account:
                try:
                    from .models import IntegrationSettings
                    logger.info(f"[test_connection] Looking for saved settings for account {account.id}")
                    saved_settings = IntegrationSettings.objects.get(
                        integration_type=integration_type,
                        account=account
                    )
                    api_key = saved_settings.config.get('apiKey')
                    logger.info(f"[test_connection] Found saved settings, has_apiKey={bool(api_key)}")
                except IntegrationSettings.DoesNotExist:
                    logger.warning(f"[test_connection] No saved settings found for {integration_type} and account {account.id}")
                    pass
        
        if not api_key:
            logger.error(f"[test_connection] No API key found in request or saved settings")
            return Response({
                'success': False,
                'error': 'API key is required'
            }, status=status.HTTP_400_BAD_REQUEST)
        
        logger.info(f"[test_connection] Testing {integration_type} connection with API key (length={len(api_key) if api_key else 0})")
        try:
            if integration_type == 'openai':
                return self._test_openai(api_key, config)
            elif integration_type == 'runware':
                return self._test_runware(api_key, request)
            else:
                return Response({
                    'success': False,
                    'error': f'Validation not supported for {integration_type}'
                }, status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            logger.error(f"Error testing {integration_type} connection: {str(e)}", exc_info=True)
            import traceback
            error_trace = traceback.format_exc()
            logger.error(f"Full traceback: {error_trace}")
            return Response({
                'success': False,
                'error': str(e)
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    
    def _test_openai(self, api_key: str, config: dict = None):
        """
        Test OpenAI API connection.
        EXACT match to reference plugin's igny8_test_connection() function.
        Reference: ai/openai-api.php line 186-309
        """
        import requests
        
        # Get model from config or use default (reference plugin: get_option('igny8_model', 'gpt-4.1'))
        model = (config or {}).get('model', 'gpt-4.1') if config else 'gpt-4.1'
        
        # Check if test with response is requested (reference plugin: $with_response parameter)
        with_response = (config or {}).get('with_response', False) if config else False
        
        if with_response:
            # Test with actual API call (reference plugin: test with chat completion)
            request_body = {
                'model': model,
                'messages': [
                    {
                        'role': 'user',
                        'content': 'test ping, reply with: OK! Ping Received. Also tell me: what is your maximum token limit that I can use in 1 request?'
                    }
                ],
                'temperature': 0.7,
            }
            
            try:
                response = requests.post(
                    'https://api.openai.com/v1/chat/completions',
                    headers={
                        'Authorization': f'Bearer {api_key}',
                        'Content-Type': 'application/json',
                    },
                    json=request_body,
                    timeout=15
                )
                
                if response.status_code >= 200 and response.status_code < 300:
                    response_data = response.json()
                    
                    if 'choices' in response_data and len(response_data['choices']) > 0:
                        response_text = response_data['choices'][0]['message']['content'].strip()
                        
                        # Extract token usage information (reference plugin: line 269-271)
                        usage = response_data.get('usage', {})
                        input_tokens = usage.get('prompt_tokens', 0)
                        output_tokens = usage.get('completion_tokens', 0)
                        total_tokens = usage.get('total_tokens', 0)
                        
                        # Calculate cost using model rates (reference plugin: line 274-275)
                        from igny8_core.utils.ai_processor import MODEL_RATES
                        rates = MODEL_RATES.get(model, {'input': 2.00, 'output': 8.00})
                        cost = (input_tokens * rates['input'] + output_tokens * rates['output']) / 1000000
                        
                        return Response({
                            'success': True,
                            'message': 'API connection and response test successful!',
                            'model_used': model,
                            'response': response_text,
                            'tokens_used': f"{input_tokens} / {output_tokens}",
                            'total_tokens': total_tokens,
                            'cost': f'${cost:.4f}',
                            'full_response': response_data,
                        })
                    else:
                        return Response({
                            'success': False,
                            'message': 'API responded but no content received',
                            'response': response.text[:500]
                        })
                else:
                    body = response.text
                    return Response({
                        'success': False,
                        'message': f'HTTP {response.status_code} – {body[:200]}'
                    }, status=response.status_code)
            except requests.exceptions.RequestException as e:
                return Response({
                    'success': False,
                    'message': str(e)
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        else:
            # Simple connection test without API call (reference plugin: GET /v1/models)
            try:
                response = requests.get(
                    'https://api.openai.com/v1/models',
                    headers={
                        'Authorization': f'Bearer {api_key}',
                    },
                    timeout=10
                )
                
                if response.status_code >= 200 and response.status_code < 300:
                    return Response({
                        'success': True,
                        'message': 'API connection successful!',
                        'model_used': model,
                        'response': 'Connection verified without API call'
                    })
                else:
                    body = response.text
                    return Response({
                        'success': False,
                        'message': f'HTTP {response.status_code} – {body[:200]}'
                    }, status=response.status_code)
            except requests.exceptions.RequestException as e:
                return Response({
                    'success': False,
                    'message': str(e)
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    
    def _test_runware(self, api_key: str, request):
        """
        Test Runware API connection using 64x64 image generation (ping validation)
        Reference: Uses same format as image generation but with minimal 64x64 size for fast validation
        """
        from igny8_core.utils.ai_processor import AIProcessor
        
        # Get account from request
        account = getattr(request, 'account', None)
        if not account:
            user = getattr(request, 'user', None)
            if user and hasattr(user, 'is_authenticated') and user.is_authenticated:
                account = getattr(user, 'account', None)
        # Fallback to default account
        if not account:
            from igny8_core.auth.models import Account
            try:
                account = Account.objects.first()
            except Exception:
                pass
        
        try:
            # EXACT match to reference plugin: core/admin/ajax.php line 4946-5003
            # Reference plugin uses: 128x128, steps=2, CFGScale=5, prompt='test image connection'
            import requests
            import uuid
            import json
            
            test_prompt = 'test image connection'
            
            # Prepare payload EXACTLY as reference plugin
            payload = [
                {
                    'taskType': 'authentication',
                    'apiKey': api_key
                },
                {
                    'taskType': 'imageInference',
                    'taskUUID': str(uuid.uuid4()),
                    'positivePrompt': test_prompt,
                    'model': 'runware:97@1',
                    'width': 128,  # Reference plugin uses 128x128, not 64x64
                    'height': 128,
                    'negativePrompt': 'text, watermark, logo, overlay, title, caption, writing on walls, writing on objects, UI, infographic elements, post title',
                    'steps': 2,  # Low steps for fast testing
                    'CFGScale': 5,
                    'numberResults': 1
                }
            ]
            
            logger.info("[_test_runware] Testing Runware API with 128x128 image generation (matching reference plugin)")
            logger.info(f"[_test_runware] Payload: {json.dumps(payload, indent=2)}")
            
            # Make API request
            response = requests.post(
                'https://api.runware.ai/v1',
                headers={'Content-Type': 'application/json'},
                json=payload,
                timeout=30
            )
            
            logger.info(f"[_test_runware] Response status: {response.status_code}")
            
            if response.status_code != 200:
                error_text = response.text
                logger.error(f"[_test_runware] HTTP error {response.status_code}: {error_text[:200]}")
                return Response({
                    'success': False,
                    'error': f'HTTP {response.status_code}: {error_text[:200]}',
                    'message': 'Runware API validation failed'
                }, status=response.status_code)
            
            # Parse response - Reference plugin checks: $body['data'][0]['imageURL']
            body = response.json()
            logger.info(f"[_test_runware] Response body type: {type(body)}")
            logger.info(f"[_test_runware] Response body: {json.dumps(body, indent=2)[:1000]}")
            
            # Reference plugin line 4996: if (isset($body['data'][0]['imageURL']))
            if isinstance(body, dict) and 'data' in body:
                data = body['data']
                if isinstance(data, list) and len(data) > 0:
                    first_item = data[0]
                    image_url = first_item.get('imageURL') or first_item.get('image_url')
                    if image_url:
                        logger.info(f"[_test_runware] Success! Image URL: {image_url[:50]}...")
                        return Response({
                            'success': True,
                            'message': '✅ Runware API connected successfully!',
                            'image_url': image_url,
                            'cost': '$0.0090',
                            'provider': 'runware',
                            'model': 'runware:97@1',
                            'size': '128x128'
                        })
            
            # Check for errors - Reference plugin line 4998: elseif (isset($body['errors'][0]['message']))
            if isinstance(body, dict) and 'errors' in body:
                errors = body['errors']
                if isinstance(errors, list) and len(errors) > 0:
                    error_msg = errors[0].get('message', 'Unknown Runware API error')
                    logger.error(f"[_test_runware] Runware API error: {error_msg}")
                    return Response({
                        'success': False,
                        'error': f'❌ {error_msg}',
                        'message': 'Runware API validation failed'
                    }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            
            # Unknown response format
            logger.error(f"[_test_runware] Unknown response format: {body}")
            return Response({
                'success': False,
                'error': '❌ Unknown response from Runware.',
                'message': 'Runware API validation failed'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        except Exception as e:
            logger.error(f"[_test_runware] Exception in Runware API test: {str(e)}", exc_info=True)
            return Response({
                'success': False,
                'error': f'Runware API test failed: {str(e)}',
                'message': 'Runware API validation failed'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    
    def generate_image(self, request, pk=None, **kwargs):
        """
        Generate image using the configured image generation service
        POST /api/v1/system/settings/integrations/image_generation/generate/
        Note: This method is called via custom URL pattern, not @action decorator
        """
        # Extract pk from kwargs if not passed as parameter (DRF passes via **kwargs)
        if not pk:
            pk = kwargs.get('pk')
        
        # Log detailed request info for debugging
        logger.info("=" * 80)
        logger.info("[generate_image] ENDPOINT CALLED - Image generation request received")
        logger.info(f"[generate_image] pk parameter: {pk}")
        logger.info(f"[generate_image] kwargs: {kwargs}")
        logger.info(f"[generate_image] request.path: {request.path}")
        logger.info(f"[generate_image] request.method: {request.method}")
        logger.info(f"[generate_image] request.META.get('PATH_INFO'): {request.META.get('PATH_INFO')}")
        logger.info(f"[generate_image] request.META.get('REQUEST_URI'): {request.META.get('REQUEST_URI', 'N/A')}")
        logger.info(f"[generate_image] request.META.get('HTTP_HOST'): {request.META.get('HTTP_HOST', 'N/A')}")
        logger.info(f"[generate_image] request.META.get('HTTP_REFERER'): {request.META.get('HTTP_REFERER', 'N/A')}")
        logger.info(f"[generate_image] request.data: {request.data}")
        
        if pk != 'image_generation':
            logger.error(f"[generate_image] Invalid pk: {pk}, expected 'image_generation'")
            return Response({
                'success': False,
                'error': f'Image generation endpoint only available for image_generation integration, got: {pk}'
            }, status=status.HTTP_400_BAD_REQUEST)
        
        # Get account
        logger.info("[generate_image] Step 1: Getting account")
        account = getattr(request, 'account', None)
        if not account:
            user = getattr(request, 'user', None)
            logger.info(f"[generate_image] No account in request, checking user: {user}")
            if user and hasattr(user, 'is_authenticated') and user.is_authenticated:
                account = getattr(user, 'account', None)
                logger.info(f"[generate_image] Got account from user: {account}")
        if not account:
            logger.info("[generate_image] No account found, trying to get first account from DB")
            from igny8_core.auth.models import Account
            try:
                account = Account.objects.first()
                logger.info(f"[generate_image] Got first account from DB: {account}")
            except Exception as e:
                logger.error(f"[generate_image] Error getting account from DB: {e}")
                pass
        
        if not account:
            logger.error("[generate_image] ERROR: No account found, returning error response")
            return Response({
                'success': False,
                'error': 'Account not found'
            }, status=status.HTTP_400_BAD_REQUEST)
        
        logger.info(f"[generate_image] Account resolved: {account.id if account else 'None'}")
        
        # Get request parameters
        logger.info("[generate_image] Step 2: Extracting request parameters")
        prompt = request.data.get('prompt', '')
        negative_prompt = request.data.get('negative_prompt', '')
        image_type = request.data.get('image_type', 'realistic')
        image_size = request.data.get('image_size', '1024x1024')
        image_format = request.data.get('image_format', 'webp')
        provider = request.data.get('provider', 'openai')
        model = request.data.get('model', 'dall-e-3')
        
        logger.info(f"[generate_image] Request parameters: provider={provider}, model={model}, image_type={image_type}, image_size={image_size}, prompt_length={len(prompt)}")
        logger.info(f"[generate_image] IMPORTANT: Using ONLY {provider.upper()} provider for this request. NOT using both providers.")
        
        if not prompt:
            logger.error("[generate_image] ERROR: Prompt is empty")
            return Response({
                'success': False,
                'error': 'Prompt is required'
            }, status=status.HTTP_400_BAD_REQUEST)
        
        # Get API key from saved settings for the specified provider only
        logger.info(f"[generate_image] Step 3: Getting API key for provider: {provider}")
        from .models import IntegrationSettings
        
        # Only fetch settings for the specified provider
        api_key = None
        integration_enabled = False
        integration_type = provider  # 'openai' or 'runware'
        
        try:
            integration_settings = IntegrationSettings.objects.get(
                integration_type=integration_type,
                account=account
            )
            api_key = integration_settings.config.get('apiKey')
            integration_enabled = integration_settings.is_active
            logger.info(f"[generate_image] {integration_type.upper()} settings found: enabled={integration_enabled}, has_key={bool(api_key)}")
        except IntegrationSettings.DoesNotExist:
            logger.warning(f"[generate_image] {integration_type.upper()} settings not found in database")
            api_key = None
            integration_enabled = False
        except Exception as e:
            logger.error(f"[generate_image] Error getting {integration_type.upper()} settings: {e}")
            api_key = None
            integration_enabled = False
        
        # Validate provider and API key
        logger.info(f"[generate_image] Step 4: Validating {provider} provider and API key")
        if provider not in ['openai', 'runware']:
            logger.error(f"[generate_image] ERROR: Invalid provider: {provider}")
            return Response({
                'success': False,
                'error': f'Invalid provider: {provider}. Must be "openai" or "runware"'
            }, status=status.HTTP_400_BAD_REQUEST)
        
        if not api_key or not integration_enabled:
            logger.error(f"[generate_image] ERROR: {provider.upper()} API key not configured or integration not enabled")
            return Response({
                'success': False,
                'error': f'{provider.upper()} API key not configured or integration not enabled'
            }, status=status.HTTP_400_BAD_REQUEST)
        
        logger.info(f"[generate_image] {provider.upper()} API key validated successfully")
        
        # Generate image using AIProcessor
        logger.info("[generate_image] Step 5: Creating AIProcessor and generating image")
        try:
            from igny8_core.utils.ai_processor import AIProcessor
            processor = AIProcessor(account=account)
            logger.info("[generate_image] AIProcessor created successfully")
            
            # Parse size
            width, height = map(int, image_size.split('x'))
            size_str = f'{width}x{height}'
            logger.info(f"[generate_image] Image size parsed: {size_str}")
            
            logger.info(f"[generate_image] Calling processor.generate_image with: provider={provider}, model={model}, size={size_str}")
            result = processor.generate_image(
                prompt=prompt,
                provider=provider,
                model=model,
                size=size_str,
                n=1,
                api_key=api_key,
                negative_prompt=negative_prompt if provider == 'runware' else None,  # OpenAI doesn't support negative prompts
            )
            
            logger.info(f"[generate_image] AIProcessor.generate_image returned: has_url={bool(result.get('url'))}, has_error={bool(result.get('error'))}")
            
            if result.get('error'):
                logger.error(f"[generate_image] ERROR from AIProcessor: {result.get('error')}")
                return Response({
                    'success': False,
                    'error': result['error']
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            
            logger.info("[generate_image] Image generation successful, returning response")
            response_data = {
                'success': True,
                'image_url': result.get('url'),
                'revised_prompt': result.get('revised_prompt'),
                'model': model,
                'provider': provider,
                'cost': f"${result.get('cost', 0):.4f}" if result.get('cost') else None,
            }
            logger.info(f"[generate_image] Returning success response: {response_data}")
            return Response(response_data)
        except Exception as e:
            logger.error(f"[generate_image] EXCEPTION in image generation: {str(e)}", exc_info=True)
            return Response({
                'success': False,
                'error': f'Failed to generate image: {str(e)}'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    
    def create(self, request):
        """Create integration settings"""
        integration_type = request.data.get('integration_type')
        if not integration_type:
            return Response({'error': 'integration_type is required'}, status=status.HTTP_400_BAD_REQUEST)
        return self.save_settings(request, integration_type)
    
    def save_settings(self, request, pk=None):
        """Save integration settings"""
        integration_type = pk  # 'openai', 'runware', 'gsc'
        
        logger.info(f"[save_settings] Called for integration_type={integration_type}, user={getattr(request, 'user', None)}, account={getattr(request, 'account', None)}")
        
        if not integration_type:
            return Response({'error': 'Integration type is required'}, status=status.HTTP_400_BAD_REQUEST)
        
        # Ensure config is a dict
        config = dict(request.data) if hasattr(request.data, 'dict') else (request.data if isinstance(request.data, dict) else {})
        logger.info(f"[save_settings] Config keys: {list(config.keys()) if isinstance(config, dict) else 'Not a dict'}")
        
        try:
            # Get account - try multiple methods
            account = getattr(request, 'account', None)
            logger.info(f"[save_settings] Account from request: {account.id if account else None}")
            
            # Fallback 1: Get from authenticated user's account
            if not account:
                user = getattr(request, 'user', None)
                if user and hasattr(user, 'is_authenticated') and user.is_authenticated:
                    try:
                        account = getattr(user, 'account', None)
                    except Exception as e:
                        logger.warning(f"Error getting account from user: {e}")
                        account = None
            
            # Fallback 2: If still no account, get default account (for development)
            if not account:
                from igny8_core.auth.models import Account
                try:
                    # Get the first account as fallback (development only)
                    account = Account.objects.first()
                except Exception as e:
                    logger.warning(f"Error getting default account: {e}")
                    account = None
            
            if not account:
                logger.error(f"[save_settings] No account found after all fallbacks")
                return Response({'error': 'Account not found. Please ensure you are logged in.'}, status=status.HTTP_400_BAD_REQUEST)
            
            logger.info(f"[save_settings] Using account: {account.id} ({account.name}, slug={account.slug}, status={account.status})")
            
            # Store integration settings in a simple model or settings table
            # For now, we'll use a simple approach - store in IntegrationSettings model
            # or use Django settings/database
            
            # Import IntegrationSettings model
            from .models import IntegrationSettings
                
            # For image_generation, ensure provider is set correctly
            if integration_type == 'image_generation':
                # Map service to provider if service is provided
                if 'service' in config and 'provider' not in config:
                    config['provider'] = config['service']
                # Ensure provider is set
                if 'provider' not in config:
                    config['provider'] = config.get('service', 'openai')
                # Set model based on provider
                if config.get('provider') == 'openai' and 'model' not in config:
                    config['model'] = config.get('imageModel', 'dall-e-3')
                elif config.get('provider') == 'runware' and 'model' not in config:
                    config['model'] = config.get('runwareModel', 'runware:97@1')
                # Ensure all image settings have defaults
                config.setdefault('image_type', 'realistic')
                config.setdefault('max_in_article_images', 2)
                config.setdefault('image_format', 'webp')
                config.setdefault('desktop_enabled', True)
                config.setdefault('mobile_enabled', True)
                
                # Set default image sizes based on provider/model
                provider = config.get('provider', 'openai')
                model = config.get('model', 'dall-e-3')
                
                if not config.get('featured_image_size'):
                    if provider == 'runware':
                        config['featured_image_size'] = '1280x832'
                    else:  # openai
                        config['featured_image_size'] = '1024x1024'
                
                if not config.get('desktop_image_size'):
                    config['desktop_image_size'] = '1024x1024'
            
            # Get or create integration settings
            logger.info(f"[save_settings] Attempting get_or_create for {integration_type} with account {account.id}")
            integration_settings, created = IntegrationSettings.objects.get_or_create(
                integration_type=integration_type,
                account=account,
                defaults={'config': config, 'is_active': config.get('enabled', False)}
            )
            logger.info(f"[save_settings] get_or_create result: created={created}, id={integration_settings.id}")
            
            if not created:
                logger.info(f"[save_settings] Updating existing settings (id={integration_settings.id})")
                integration_settings.config = config
                integration_settings.is_active = config.get('enabled', False)
                integration_settings.save()
                logger.info(f"[save_settings] Settings updated successfully")
            
            logger.info(f"[save_settings] Successfully saved settings for {integration_type}")
            return Response({
                'success': True,
                'message': f'{integration_type.upper()} settings saved successfully'
            })
                
        except Exception as e:
            logger.error(f"Error saving integration settings for {integration_type}: {str(e)}", exc_info=True)
            import traceback
            error_trace = traceback.format_exc()
            logger.error(f"Full traceback: {error_trace}")
            return Response({
                'error': f'Failed to save settings: {str(e)}'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    
    def get_settings(self, request, pk=None):
        """Get integration settings - defaults to AWS-admin settings if account doesn't have its own"""
        integration_type = pk
        
        if not integration_type:
            return Response({
                'success': False,
                'error': 'Integration type is required'
            }, status=status.HTTP_400_BAD_REQUEST)
        
        try:
            # Get account - try multiple methods (same as save_settings)
            account = getattr(request, 'account', None)
            
            # Fallback 1: Get from authenticated user's account
            if not account:
                user = getattr(request, 'user', None)
                if user and hasattr(user, 'is_authenticated') and user.is_authenticated:
                    try:
                        account = getattr(user, 'account', None)
                    except Exception as e:
                        logger.warning(f"Error getting account from user: {e}")
                        account = None
            
            from .models import IntegrationSettings
            
            # Get account-specific settings
            if account:
                try:
                    integration_settings = IntegrationSettings.objects.get(
                        integration_type=integration_type,
                        account=account
                    )
                    return Response({
                        'success': True,
                        'data': integration_settings.config
                    })
                except IntegrationSettings.DoesNotExist:
                    pass
                except Exception as e:
                    logger.error(f"Error getting account-specific settings: {e}", exc_info=True)
            
            # Return empty config if no settings found
            return Response({
                'success': True,
                'data': {}
            })
        except Exception as e:
            logger.error(f"Unexpected error in get_settings for {integration_type}: {e}", exc_info=True)
            return Response({
                'success': False,
                'error': f'Failed to get settings: {str(e)}'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    
    @action(detail=False, methods=['get'], url_path='image_generation', url_name='image_generation_settings')
    def get_image_generation_settings(self, request):
        """Get image generation settings for current account"""
        account = getattr(request, 'account', None)
        
        if not account:
            # Fallback to user's account
            user = getattr(request, 'user', None)
            if user and hasattr(user, 'is_authenticated') and user.is_authenticated:
                account = getattr(user, 'account', None)
            # Fallback to default account
            if not account:
                from igny8_core.auth.models import Account
                try:
                    account = Account.objects.first()
                except Exception:
                    pass
        
        if not account:
            return Response({
                'error': 'Account not found',
                'type': 'AuthenticationError'
            }, status=status.HTTP_401_UNAUTHORIZED)
        
        try:
            from .models import IntegrationSettings
            integration = IntegrationSettings.objects.get(
                account=account,
                integration_type='image_generation',
                is_active=True
            )
            
            config = integration.config or {}
            
            # Debug: Log what's actually in the config
            logger.info(f"[get_image_generation_settings] Full config: {config}")
            logger.info(f"[get_image_generation_settings] Config keys: {list(config.keys())}")
            logger.info(f"[get_image_generation_settings] model field: {config.get('model')}")
            logger.info(f"[get_image_generation_settings] imageModel field: {config.get('imageModel')}")
            
            # Get model - try 'model' first, then 'imageModel' as fallback
            model = config.get('model') or config.get('imageModel') or 'dall-e-3'
            
            # Set defaults for image sizes if not present
            provider = config.get('provider', 'openai')
            default_featured_size = '1280x832' if provider == 'runware' else '1024x1024'
            
            return Response({
                'success': True,
                'config': {
                    'provider': config.get('provider', 'openai'),
                    'model': model,
                    'image_type': config.get('image_type', 'realistic'),
                    'max_in_article_images': config.get('max_in_article_images', 2),
                    'image_format': config.get('image_format', 'webp'),
                    'desktop_enabled': config.get('desktop_enabled', True),
                    'mobile_enabled': config.get('mobile_enabled', True),
                    'featured_image_size': config.get('featured_image_size', default_featured_size),
                    'desktop_image_size': config.get('desktop_image_size', '1024x1024'),
                }
            }, status=status.HTTP_200_OK)
        except IntegrationSettings.DoesNotExist:
            return Response({
                'success': True,
                'config': {
                    'provider': 'openai',
                    'model': 'dall-e-3',
                    'image_type': 'realistic',
                    'max_in_article_images': 2,
                    'image_format': 'webp',
                    'desktop_enabled': True,
                    'mobile_enabled': True,
                }
            }, status=status.HTTP_200_OK)
        except Exception as e:
            logger.error(f"[get_image_generation_settings] Error: {str(e)}", exc_info=True)
            return Response({
                'error': str(e),
                'type': 'ServerError'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    
    @action(detail=False, methods=['get'], url_path='task_progress/(?P<task_id>[^/.]+)', url_name='task-progress')
    def task_progress(self, request, task_id=None):
        """
        Get Celery task progress status
        GET /api/v1/system/settings/task_progress/<task_id>/
        """
        if not task_id:
            return Response(
                {'error': 'Task ID is required'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        import logging
        logger = logging.getLogger(__name__)
        
        try:
            # Try to import Celery AsyncResult
            try:
                from celery.result import AsyncResult
                from kombu.exceptions import OperationalError as KombuOperationalError
                # Try to import redis ConnectionError, but it might not be available
                try:
                    from redis.exceptions import ConnectionError as RedisConnectionError
                except ImportError:
                    # Redis might not be installed or ConnectionError might not exist
                    RedisConnectionError = ConnectionError
            except ImportError:
                logger.warning("Celery not available - task progress cannot be retrieved")
                return Response({
                    'state': 'PENDING',
                    'meta': {
                        'percentage': 0,
                        'message': 'Celery not available - cannot retrieve task status',
                        'error': 'Celery not configured'
                    }
                }, status=status.HTTP_503_SERVICE_UNAVAILABLE)
            
            try:
                # Create AsyncResult - this should not raise an exception even if task doesn't exist
                task = AsyncResult(task_id)
                
                # Safely get task state - accessing task.state can raise ValueError if exception info is malformed
                # or ConnectionError if backend is unavailable
                try:
                    task_state = task.state
                except (ValueError, KeyError) as state_exc:
                    # Task has malformed exception info - try to get error from multiple sources
                    logger.warning(f"Error accessing task.state (malformed exception info): {str(state_exc)}")
                    error_msg = 'Task failed - exception details unavailable'
                    error_type = 'UnknownError'
                    request_steps = []
                    response_steps = []
                    
                    # First, try to get from backend's stored meta (most reliable for our update_state calls)
                    try:
                        backend = task.backend
                        if hasattr(backend, 'get_task_meta'):
                            stored_meta = backend.get_task_meta(task_id)
                            if stored_meta and isinstance(stored_meta, dict):
                                meta = stored_meta.get('meta', {})
                                if isinstance(meta, dict):
                                    if 'error' in meta:
                                        error_msg = meta.get('error')
                                    if 'error_type' in meta:
                                        error_type = meta.get('error_type', error_type)
                                    if 'request_steps' in meta:
                                        request_steps = meta.get('request_steps', [])
                                    if 'response_steps' in meta:
                                        response_steps = meta.get('response_steps', [])
                    except Exception as e:
                        logger.debug(f"Error getting from backend meta: {str(e)}")
                    
                    # Try to get error from task.result
                    if error_msg == 'Task failed - exception details unavailable':
                        try:
                            if hasattr(task, 'result'):
                                result = task.result
                                if isinstance(result, dict):
                                    error_msg = result.get('error', error_msg)
                                    error_type = result.get('error_type', error_type)
                                    request_steps = result.get('request_steps', request_steps)
                                    response_steps = result.get('response_steps', response_steps)
                                elif isinstance(result, str):
                                    error_msg = result
                        except Exception as e:
                            logger.debug(f"Error extracting error from task.result: {str(e)}")
                    
                    # Also try to get error from task.info
                    if error_msg == 'Task failed - exception details unavailable':
                        try:
                            if hasattr(task, 'info') and task.info:
                                if isinstance(task.info, dict):
                                    if 'error' in task.info:
                                        error_msg = task.info['error']
                                    if 'error_type' in task.info:
                                        error_type = task.info['error_type']
                                    if 'request_steps' in task.info:
                                        request_steps = task.info.get('request_steps', request_steps)
                                    if 'response_steps' in task.info:
                                        response_steps = task.info.get('response_steps', response_steps)
                        except Exception as e:
                            logger.debug(f"Error extracting error from task.info: {str(e)}")
                    
                    return Response({
                        'state': 'FAILURE',
                        'meta': {
                            'error': error_msg,
                            'error_type': error_type,
                            'percentage': 0,
                            'message': f'Error: {error_msg}',
                            'request_steps': request_steps,
                            'response_steps': response_steps,
                        }
                    })
                except (KombuOperationalError, RedisConnectionError, ConnectionError) as conn_exc:
                    # Backend connection error - task might not be registered yet or backend is down
                    logger.warning(f"Backend connection error accessing task.state for {task_id}: {type(conn_exc).__name__}: {str(conn_exc)}")
                    return Response({
                        'state': 'PENDING',
                        'meta': {
                            'percentage': 0,
                            'message': 'Task is being queued...',
                            'phase': 'initializing',
                            'error': None  # Don't show as error, just pending
                        }
                    })
                except Exception as state_exc:
                    logger.error(f"Unexpected error accessing task.state: {type(state_exc).__name__}: {str(state_exc)}")
                    return Response({
                        'state': 'UNKNOWN',
                        'meta': {
                            'error': f'Error accessing task: {str(state_exc)}',
                            'percentage': 0,
                            'message': f'Error: {str(state_exc)}',
                        }
                    }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                
                # Check if task exists and is accessible
                if task_state is None:
                    # Task doesn't exist or hasn't been registered yet
                    return Response({
                        'state': 'PENDING',
                        'meta': {
                            'percentage': 0,
                            'message': 'Task not found or not yet registered',
                            'phase': 'initializing',
                        }
                    })
                
                # Safely get task info/result
                # Try to get error from multiple sources
                task_result = None
                task_info = None
                error_message = None
                error_type = None
                
                # First, try to get from backend's stored meta (most reliable for our update_state calls)
                try:
                    backend = task.backend
                    if hasattr(backend, 'get_task_meta'):
                        stored_meta = backend.get_task_meta(task_id)
                        if stored_meta and isinstance(stored_meta, dict):
                            meta = stored_meta.get('meta', {})
                            if isinstance(meta, dict):
                                if 'error' in meta:
                                    error_message = meta.get('error')
                                    error_type = meta.get('error_type', 'UnknownError')
                except Exception as backend_err:
                    logger.debug(f"Could not get from backend meta: {backend_err}")
                
                try:
                    # Try to get result first - this often has the actual error
                    if not error_message and hasattr(task, 'result'):
                        try:
                            task_result = task.result
                            # If result is a dict with error, extract it
                            if isinstance(task_result, dict):
                                if 'error' in task_result:
                                    error_message = task_result.get('error')
                                    error_type = task_result.get('error_type', 'UnknownError')
                                elif 'success' in task_result and not task_result.get('success'):
                                    error_message = task_result.get('error', 'Task failed')
                                    error_type = task_result.get('error_type', 'UnknownError')
                        except Exception:
                            pass  # Will try task.info next
                except Exception:
                    pass
                
                # Then try task.info
                if not error_message and hasattr(task, 'info'):
                    try:
                        task_info = task.info
                        if isinstance(task_info, dict):
                            if 'error' in task_info:
                                error_message = task_info.get('error')
                                error_type = task_info.get('error_type', 'UnknownError')
                    except (ValueError, KeyError, AttributeError) as info_exc:
                        # Log the actual exception that occurred
                        logger.error(f"Error accessing task.info for {task_id}: {type(info_exc).__name__}: {str(info_exc)}", exc_info=True)
                        # Try to get error from traceback if available
                        try:
                            if hasattr(task, 'traceback'):
                                error_message = f"Task failed: {str(task.traceback)}"
                        except:
                            pass
                    except (KombuOperationalError, RedisConnectionError, ConnectionError) as conn_exc:
                        # Backend connection error - task might not be registered yet
                        logger.warning(f"Backend connection error accessing task.info for {task_id}: {str(conn_exc)}")
                        task_info = None
                    except Exception as e:
                        logger.error(f"Unexpected error accessing task.info: {type(e).__name__}: {str(e)}", exc_info=True)
                else:
                    if not hasattr(task, 'info'):
                        task_info = None
                
                # If still no error message, try to get from task.result again
                if not error_message and hasattr(task, 'result'):
                    try:
                        task_result = task.result
                        if isinstance(task_result, dict):
                            if 'error' in task_result:
                                error_message = task_result.get('error')
                                error_type = task_result.get('error_type', 'UnknownError')
                            elif 'success' in task_result and not task_result.get('success'):
                                error_message = task_result.get('error', 'Task failed')
                                error_type = task_result.get('error_type', 'UnknownError')
                        elif isinstance(task_result, str):
                            error_message = task_result
                        elif isinstance(task_result, Exception):
                            error_message = str(task_result)
                            error_type = type(task_result).__name__
                    except (ValueError, KeyError) as result_exc:
                        logger.warning(f"Error accessing task.result: {str(result_exc)}")
                        task_result = None
                    except (KombuOperationalError, RedisConnectionError, ConnectionError) as conn_exc:
                        # Backend connection error
                        logger.warning(f"Backend connection error accessing task.result for {task_id}: {str(conn_exc)}")
                        task_result = None
                    except Exception as info_error:
                        logger.warning(f"Unexpected error accessing task result: {str(info_error)}")
                        task_result = None
                
                # Use extracted error or fallback - try traceback as last resort
                if not error_message:
                    try:
                        if hasattr(task, 'traceback') and task.traceback:
                            error_message = f"Task failed: {str(task.traceback)}"
                    except Exception:
                        pass
                
                if not error_message:
                    error_message = f"Task failed - check Celery worker logs for task {task_id}"
                
                if task_state == 'PROGRESS':
                    meta = task_info or {}
                    response_meta = {
                        'current': meta.get('current', 0) if isinstance(meta, dict) else 0,
                        'total': meta.get('total', 0) if isinstance(meta, dict) else 0,
                        'percentage': meta.get('percentage', 0) if isinstance(meta, dict) else 0,
                        'message': meta.get('message', 'Processing...') if isinstance(meta, dict) else 'Processing...',
                        'phase': meta.get('phase', 'processing') if isinstance(meta, dict) else 'processing',
                        'current_item': meta.get('current_item') if isinstance(meta, dict) else None,
                        'completed': meta.get('completed', 0) if isinstance(meta, dict) else 0,
                        # Image generation progress fields
                        'current_image': meta.get('current_image') if isinstance(meta, dict) else None,
                        'current_image_id': meta.get('current_image_id') if isinstance(meta, dict) else None,
                        'current_image_progress': meta.get('current_image_progress') if isinstance(meta, dict) else None,
                        'total_images': meta.get('total_images') if isinstance(meta, dict) else None,
                        'failed': meta.get('failed', 0) if isinstance(meta, dict) else 0,
                        'results': meta.get('results', []) if isinstance(meta, dict) else [],
                    }
                    # Include step logs if available
                    if isinstance(meta, dict):
                        if 'request_steps' in meta:
                            response_meta['request_steps'] = meta['request_steps']
                        if 'response_steps' in meta:
                            response_meta['response_steps'] = meta['response_steps']
                        # Include image_queue if available (for image generation)
                        if 'image_queue' in meta:
                            response_meta['image_queue'] = meta['image_queue']
                    return Response({
                        'state': task_state,
                        'meta': response_meta
                    })
                elif task_state == 'SUCCESS':
                    result = task_result or {}
                    meta = result if isinstance(result, dict) else {}
                    response_meta = {
                        'percentage': 100,
                        'message': meta.get('message', 'Task completed successfully') if isinstance(meta, dict) else 'Task completed successfully',
                        'result': result,
                        'details': meta if isinstance(meta, dict) else {},
                    }
                    # Include step logs if available
                    if isinstance(meta, dict):
                        if 'request_steps' in meta:
                            response_meta['request_steps'] = meta['request_steps']
                        if 'response_steps' in meta:
                            response_meta['response_steps'] = meta['response_steps']
                    return Response({
                        'state': task_state,
                        'meta': response_meta
                    })
                elif task_state == 'FAILURE':
                    # Try to get error from task.info meta first (this is where run_ai_task sets it)
                    if not error_message and isinstance(task_info, dict):
                        error_message = task_info.get('error') or task_info.get('message', '')
                        error_type = task_info.get('error_type', 'UnknownError')
                        # Also check if message contains error info
                        if not error_message and 'message' in task_info:
                            msg = task_info.get('message', '')
                            if msg and 'Error:' in msg:
                                error_message = msg.replace('Error: ', '')
                    
                    # Use extracted error_message if available, otherwise try to get from error_info
                    if not error_message:
                        error_info = task_info
                        if isinstance(error_info, Exception):
                            error_message = str(error_info)
                        elif isinstance(error_info, dict):
                            error_message = error_info.get('error') or error_info.get('message', '') or str(error_info)
                        elif error_info:
                            error_message = str(error_info)
                    
                    # Final fallback - ensure we always have an error message
                    if not error_message or error_message.strip() == '':
                        error_message = f'Task execution failed - check Celery worker logs for task {task_id}'
                        error_type = 'ExecutionError'
                    
                    # If still no error message, try to get from task backend directly
                    if not error_message:
                        try:
                            # Try to get from backend's stored result
                            backend = task.backend
                            if hasattr(backend, 'get'):
                                stored = backend.get(task_id)
                                if stored and isinstance(stored, dict):
                                    if 'error' in stored:
                                        error_message = stored['error']
                                    elif isinstance(stored.get('result'), dict) and 'error' in stored['result']:
                                        error_message = stored['result']['error']
                        except Exception as backend_err:
                            logger.warning(f"Error getting from backend: {backend_err}")
                    
                    # Final fallback
                    if not error_message:
                        error_message = 'Task failed - check backend logs for details'
                    
                    response_meta = {
                        'error': error_message,
                        'percentage': 0,
                        'message': f'Error: {error_message}',
                    }
                    
                    # Include error_type if available
                    if error_type:
                        response_meta['error_type'] = error_type
                    
                    # Include step logs if available (from task result or error_info)
                    result = task_result or {}
                    meta = result if isinstance(result, dict) else (task_info if isinstance(task_info, dict) else {})
                    if isinstance(meta, dict):
                        if 'request_steps' in meta:
                            response_meta['request_steps'] = meta['request_steps']
                        if 'response_steps' in meta:
                            response_meta['response_steps'] = meta['response_steps']
                        # Also include error_type if available in meta
                        if 'error_type' in meta and not error_type:
                            response_meta['error_type'] = meta['error_type']
                        # Also check for error in meta directly
                        if 'error' in meta and not error_message:
                            error_message = meta['error']
                            response_meta['error'] = error_message
                        if 'error_type' in meta and not error_type:
                            error_type = meta['error_type']
                            response_meta['error_type'] = error_type
                    
                    return Response({
                        'state': task_state,
                        'meta': response_meta
                    })
                else:
                    # PENDING, STARTED, or other states
                    return Response({
                        'state': task_state,
                        'meta': {
                            'percentage': 0,
                            'message': 'Task is starting...',
                            'phase': 'initializing',
                        }
                    })
            except (KombuOperationalError, RedisConnectionError, ConnectionError) as conn_error:
                # Backend connection error - task might not be registered yet or backend is down
                logger.warning(f"Backend connection error for task {task_id}: {type(conn_error).__name__}: {str(conn_error)}")
                return Response({
                    'state': 'PENDING',
                    'meta': {
                        'percentage': 0,
                        'message': 'Task is being queued...',
                        'phase': 'initializing',
                        'error': None  # Don't show as error, just pending
                    }
                })
            except Exception as task_error:
                logger.error(f"Error accessing Celery task {task_id}: {type(task_error).__name__}: {str(task_error)}", exc_info=True)
                return Response({
                    'state': 'UNKNOWN',
                    'meta': {
                        'percentage': 0,
                        'message': f'Error accessing task: {str(task_error)}',
                        'error': str(task_error)
                    }
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                
        except Exception as e:
            # Check if it's a connection-related error - treat as PENDING instead of error
            error_type = type(e).__name__
            error_str = str(e).lower()
            is_connection_error = (
                'connection' in error_str or 
                'connect' in error_str or
                'timeout' in error_str or
                'unavailable' in error_str or
                'network' in error_str or
                error_type in ('ConnectionError', 'TimeoutError', 'OperationalError')
            )
            
            if is_connection_error:
                logger.warning(f"Connection error getting task progress for {task_id}: {error_type}: {str(e)}")
                return Response({
                    'state': 'PENDING',
                    'meta': {
                        'percentage': 0,
                        'message': 'Task is being queued...',
                        'phase': 'initializing',
                        'error': None
                    }
                })
            else:
                logger.error(f"Error getting task progress for {task_id}: {error_type}: {str(e)}", exc_info=True)
                return Response(
                    {
                        'state': 'ERROR',
                        'meta': {
                            'error': f'Error getting task status: {str(e)}',
                            'percentage': 0,
                            'message': f'Error: {str(e)}'
                        }
                    },
                    status=status.HTTP_500_INTERNAL_SERVER_ERROR
                )

