# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
"""
JSON code renderer for code generation.
"""

from .codeRendererBaseTemplate import BaseCodeRenderer
from modules.datamodels.datamodelDocument import RenderedDocument
from typing import Dict, Any, List, Optional
import json

class RendererCodeJson(BaseCodeRenderer):
    """Renders JSON code files."""
    
    @classmethod
    def getSupportedFormats(cls) -> List[str]:
        """Return supported JSON formats."""
        return ['json']
    
    @classmethod
    def getFormatAliases(cls) -> List[str]:
        """Return format aliases."""
        return []
    
    @classmethod
    def getPriority(cls) -> int:
        """Return priority for JSON code renderer."""
        return 85  # Higher than document renderer (80) for code generation
    
    @classmethod
    def getOutputStyle(cls, formatName: Optional[str] = None) -> str:
        """Return output style classification: JSON is structured data format."""
        return 'code'
    
    async def renderCodeFiles(
        self, 
        codeFiles: List[Dict[str, Any]], 
        metadata: Dict[str, Any],
        userPrompt: str = None
    ) -> List[RenderedDocument]:
        """
        Render JSON code files.
        For single file: output as-is
        For multiple files: output separately (each file is independent JSON)
        """
        renderedDocs = []
        
        for codeFile in codeFiles:
            if not self._validateCodeFile(codeFile):
                self.logger.warning(f"Invalid code file: {codeFile.get('filename', 'unknown')}")
                continue
            
            filename = codeFile['filename']
            content = codeFile['content']
            
            # Validate JSON syntax and extract statistics
            parsed = None
            try:
                parsed = json.loads(content)  # Validate JSON
            except json.JSONDecodeError as e:
                self.logger.warning(f"Invalid JSON in {filename}: {e}")
                # Could fix/format JSON here if needed
            
            # Format JSON (pretty print)
            try:
                if parsed is None:
                    parsed = json.loads(content)
                formattedContent = json.dumps(parsed, indent=2, ensure_ascii=False)
            except Exception:
                formattedContent = content  # Use original if formatting fails
            
            # Extract JSON statistics for validation
            jsonStats = self._extractJsonStatistics(parsed) if parsed else {}
            
            # Merge file-specific metadata with project metadata
            fileMetadata = dict(metadata) if metadata else {}
            fileMetadata.update({
                "filename": filename,
                "fileType": "json",
                "statistics": jsonStats
            })
            
            renderedDocs.append(
                RenderedDocument(
                    documentData=formattedContent.encode('utf-8'),
                    mimeType="application/json",
                    filename=filename,
                    metadata=fileMetadata
                )
            )
        
        return renderedDocs
    
    async def render(self, extractedContent: Dict[str, Any], title: str, userPrompt: str = None, aiService=None) -> List[RenderedDocument]:
        """
        Render method for document generation compatibility.
        Delegates to document renderer if needed, or handles code files directly.
        """
        # Check if this is code generation (has files array) or document generation (has documents array)
        if "files" in extractedContent:
            # Code generation path - use renderCodeFiles
            files = extractedContent.get("files", [])
            metadata = extractedContent.get("metadata", {})
            return await self.renderCodeFiles(files, metadata, userPrompt)
        else:
            # Document generation path - delegate to document renderer
            # Import here to avoid circular dependency
            from .rendererJson import RendererJson
            documentRenderer = RendererJson(self.services)
            return await documentRenderer.render(extractedContent, title, userPrompt, aiService)
    
    def _extractJsonStatistics(self, parsed: Any) -> Dict[str, Any]:
        """Extract JSON statistics for validation (object count, array count, key count)."""
        try:
            stats = {
                "isArray": isinstance(parsed, list),
                "isObject": isinstance(parsed, dict),
                "itemCount": 0,
                "keyCount": 0
            }
            
            if isinstance(parsed, list):
                stats["itemCount"] = len(parsed)
                # Count nested objects/arrays
                objectCount = sum(1 for item in parsed if isinstance(item, dict))
                arrayCount = sum(1 for item in parsed if isinstance(item, list))
                stats["objectCount"] = objectCount
                stats["arrayCount"] = arrayCount
            elif isinstance(parsed, dict):
                stats["keyCount"] = len(parsed)
                stats["keys"] = list(parsed.keys())
                # Count nested objects/arrays
                objectCount = sum(1 for v in parsed.values() if isinstance(v, dict))
                arrayCount = sum(1 for v in parsed.values() if isinstance(v, list))
                stats["objectCount"] = objectCount
                stats["arrayCount"] = arrayCount
            
            return stats
        except Exception as e:
            self.logger.warning(f"JSON statistics extraction failed: {e}")
            return {}
