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

from .codeRendererBaseTemplate import BaseCodeRenderer
from modules.datamodels.datamodelDocument import RenderedDocument
from typing import Dict, Any, List, Optional
import xml.etree.ElementTree as ET
from xml.dom import minidom

class RendererCodeXml(BaseCodeRenderer):
    """Renders XML code files."""
    
    @classmethod
    def getSupportedFormats(cls) -> List[str]:
        """Return supported XML formats."""
        return ['xml']
    
    @classmethod
    def getFormatAliases(cls) -> List[str]:
        """Return format aliases."""
        return []
    
    @classmethod
    def getPriority(cls) -> int:
        """Return priority for XML code renderer."""
        return 80
    
    @classmethod
    def getOutputStyle(cls, formatName: Optional[str] = None) -> str:
        """Return output style classification: XML 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 XML code files.
        Validates XML syntax and formats (pretty print).
        """
        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 and format XML
            formattedContent = self._validateAndFormatXml(content)
            
            # Extract XML statistics for validation
            xmlStats = self._extractXmlStatistics(formattedContent)
            
            # Merge file-specific metadata with project metadata
            fileMetadata = dict(metadata) if metadata else {}
            fileMetadata.update({
                "filename": filename,
                "fileType": "xml",
                "statistics": xmlStats
            })
            
            renderedDocs.append(
                RenderedDocument(
                    documentData=formattedContent.encode('utf-8'),
                    mimeType="application/xml",
                    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.
        For XML, we only support code generation (no document renderer exists yet).
        """
        # Check if this is code generation (has files 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 - not supported yet, return error
            self.logger.warning("XML document generation not supported, only code generation")
            return [
                RenderedDocument(
                    documentData=f"XML document generation not yet supported".encode('utf-8'),
                    mimeType="text/plain",
                    filename="error.txt",
                    metadata={}
                )
            ]
    
    def _validateAndFormatXml(self, content: str) -> str:
        """Validate XML syntax and format (pretty print)."""
        try:
            # Parse XML to validate
            root = ET.fromstring(content)
            
            # Format XML (pretty print)
            rough_string = ET.tostring(root, encoding='unicode')
            reparsed = minidom.parseString(rough_string)
            formatted = reparsed.toprettyxml(indent="  ")
            
            # Remove extra blank lines
            lines = [line for line in formatted.split('\n') if line.strip()]
            return '\n'.join(lines)
            
        except ET.ParseError as e:
            self.logger.warning(f"Invalid XML: {e}, returning original content")
            return content
        except Exception as e:
            self.logger.warning(f"XML formatting failed: {e}, returning original content")
            return content
    
    def _extractXmlStatistics(self, content: str) -> Dict[str, Any]:
        """Extract XML statistics for validation (element count, attribute count, root element)."""
        try:
            root = ET.fromstring(content)
            
            # Count all elements recursively
            elementCount = len(list(root.iter()))
            
            # Count attributes
            attributeCount = sum(len(elem.attrib) for elem in root.iter())
            
            # Get root element name
            rootElement = root.tag
            
            return {
                "elementCount": elementCount,
                "attributeCount": attributeCount,
                "rootElement": rootElement,
                "hasRoot": True
            }
        except Exception as e:
            self.logger.warning(f"XML statistics extraction failed: {e}")
            return {}
