"""
🎯 Typst Engine - Clean Implementation
=====================================
Optimized Typst engine with system CLI integration
"""

import os
import subprocess
import tempfile
import logging
from pathlib import Path
from typing import Dict, Any, Optional
from datetime import datetime

class TypstEngine:
    """
    Clean Typst engine using system CLI
    Focused on reliability and markdown→Typst conversion
    """
    
    def __init__(self):
        """Initialize Typst engine"""
        self.logger = logging.getLogger(__name__)
        self.base_dir = Path(__file__).parent.parent
        
        # Check if Typst CLI is available
        self.typst_available = self._check_typst_cli()
        
        if not self.typst_available:
            self.logger.warning("System Typst CLI not found - this engine will not function")
    
    def _check_typst_cli(self) -> bool:
        """Check if Typst CLI is available in system PATH"""
        try:
            result = subprocess.run(
                ["typst", "--version"], 
                capture_output=True, 
                text=True, 
                timeout=5
            )
            if result.returncode == 0:
                self.logger.info(f"Typst CLI found: {result.stdout.strip()}")
                return True
        except (subprocess.TimeoutExpired, FileNotFoundError):
            pass
        return False
    
    def generate(self, 
                 content: str,
                 output_file: Path,
                 template: str = "technical",
                 **kwargs) -> Dict[str, Any]:
        """
        Generate PDF using Typst CLI
        
        Args:
            content: Markdown content
            output_file: Output PDF path
            template: Template name
            **kwargs: Template parameters
            
        Returns:
            Generation result
        """
        if not self.typst_available:
            raise RuntimeError("Typst CLI not available")
        
        try:
            # Convert markdown to Typst
            typst_content = self._markdown_to_typst(content, template, **kwargs)
            
            # Create temporary Typst file
            with tempfile.NamedTemporaryFile(mode='w', suffix='.typ', delete=False, encoding='utf-8') as f:
                f.write(typst_content)
                temp_typst_file = f.name
            
            try:
                # Compile with Typst CLI
                result = subprocess.run([
                    'typst', 'compile', temp_typst_file, str(output_file)
                ], 
                capture_output=True, 
                text=True, 
                timeout=60,
                encoding='utf-8',
                env={**os.environ, 'PYTHONIOENCODING': 'utf-8'})
                
                if result.returncode == 0:
                    file_size = output_file.stat().st_size if output_file.exists() else 0
                    return {
                        "success": True,
                        "output_file": str(output_file),
                        "template": template,
                        "engine": "typst",
                        "file_size_bytes": file_size,
                        "timestamp": datetime.now().isoformat()
                    }
                else:
                    error_msg = result.stderr or result.stdout or "Unknown Typst error"
                    self.logger.error(f"Typst compilation failed: {error_msg}")
                    raise RuntimeError(f"Typst compilation failed: {error_msg}")
                    
            finally:
                # Cleanup temporary file
                try:
                    os.unlink(temp_typst_file)
                except OSError:
                    pass
                    
        except Exception as e:
            self.logger.error(f"Typst generation error: {e}")
            raise
    
    def _markdown_to_typst(self, markdown_content: str, template: str, **kwargs) -> str:
        """
        Convert markdown content to Typst syntax
        
        This is a simplified, clean conversion focused on reliability
        """
        # Get template
        typst_template = self._get_template(template)
        
        # Basic metadata
        title = kwargs.get('title', 'Document')
        author = kwargs.get('author', 'Generated by WOT-PDF')
        
        # Apply template with metadata
        header = typst_template.format(
            title=title,
            author=author,
            date=datetime.now().strftime("%B %d, %Y")
        )
        
        # Convert markdown to Typst content
        typst_content = self._convert_markdown_syntax(markdown_content)
        
        return header + "\n\n" + typst_content
    
    def _convert_markdown_syntax(self, content: str) -> str:
        """
        Enhanced markdown to Typst conversion
        Supports advanced formatting and special elements
        """
        lines = content.split('\n')
        typst_lines = []
        in_code_block = False
        in_table = False
        table_headers = []
        table_rows = []
        code_lang = ""
        
        for i, line in enumerate(lines):
            # Code blocks
            if line.strip().startswith('```'):
                if not in_code_block:
                    # Starting code block
                    in_code_block = True
                    code_lang = line.strip()[3:].strip()
                    if code_lang:
                        typst_lines.append(f"```{code_lang}")
                    else:
                        typst_lines.append("```")
                else:
                    # Ending code block
                    in_code_block = False
                    typst_lines.append("```")
                continue
            
            # If inside code block, preserve line as-is
            if in_code_block:
                typst_lines.append(line)
                continue
            
            # Table detection
            if '|' in line and line.strip().startswith('|') and line.strip().endswith('|'):
                self.logger.debug(f"Table line detected: {line}")
                if not in_table:
                    # Starting a table
                    in_table = True
                    table_headers = [cell.strip() for cell in line.strip().split('|')[1:-1]]
                    self.logger.debug(f"Table headers: {table_headers}")
                    continue
                elif line.strip().replace('|', '').replace('-', '').replace(' ', '') == '':
                    # Table separator line, skip
                    self.logger.debug("Table separator line, skipping")
                    continue
                else:
                    # Table data row
                    table_row = [cell.strip() for cell in line.strip().split('|')[1:-1]]
                    table_rows.append(table_row)
                    self.logger.debug(f"Table row added: {table_row}")
                    # Check if next line is still table
                    if i + 1 >= len(lines) or not (lines[i + 1].strip().startswith('|') and lines[i + 1].strip().endswith('|')):
                        # End of table, output it
                        self.logger.debug(f"End of table, creating Typst table with {len(table_headers)} headers and {len(table_rows)} rows")
                        typst_table = self._create_typst_table(table_headers, table_rows)
                        typst_lines.append(typst_table)
                        self.logger.debug(f"Generated Typst table: {typst_table}")
                        in_table = False
                        table_headers = []
                        table_rows = []
                    continue
            
            # Headers
            if line.startswith('#') and not in_code_block:
                level = len(line) - len(line.lstrip('#'))
                header_text = line.lstrip('# ').strip()
                if level <= 6:
                    typst_lines.append(f"{'=' * level} {header_text}")
                continue
            
            # Horizontal rules
            if line.strip() in ['---', '***', '___']:
                typst_lines.append("#line(length: 100%)")
                continue
            
            # Lists (improved handling)
            if line.strip().startswith(('- ', '* ', '+ ')):
                indent = len(line) - len(line.lstrip())
                item_text = line.strip()[2:].strip()
                # Convert markdown formatting in list items
                item_text = self._convert_inline_formatting(item_text)
                typst_lines.append(' ' * indent + f"- {item_text}")
                continue
            
            # Numbered lists
            if line.strip() and line.strip()[0].isdigit() and '. ' in line.strip():
                indent = len(line) - len(line.lstrip())
                item_text = line.strip().split('. ', 1)[1] if '. ' in line.strip() else line.strip()
                item_text = self._convert_inline_formatting(item_text)
                typst_lines.append(' ' * indent + f"+ {item_text}")
                continue
            
            # Block quotes
            if line.strip().startswith('> '):
                quote_text = line.strip()[2:]
                quote_text = self._convert_inline_formatting(quote_text)
                typst_lines.append(f"#quote[{quote_text}]")
                continue
            
            # Regular text with inline formatting
            if line.strip():
                converted_line = self._convert_inline_formatting(line)
                typst_lines.append(converted_line)
            else:
                typst_lines.append("")
        
        return '\n'.join(typst_lines)
    
    def _create_typst_table(self, headers: list, rows: list) -> str:
        """Create Typst table from markdown table data"""
        if not headers:
            return ""
        
        # Calculate column count
        col_count = len(headers)
        
        # Create table header with white text on blue background and center alignment
        header_cells = ', '.join([f'[#text(fill: white, weight: "bold")[#align(center)[{self._escape_typst_text(header)}]]]' for header in headers])
        
        # Create table rows with smart alignment
        table_rows = []
        for row in rows:
            # Pad row if necessary
            while len(row) < col_count:
                row.append("")
            # Smart alignment based on content
            aligned_cells = []
            for cell in row[:col_count]:
                cell_content = cell.strip()
                # Escape special characters in cell content
                escaped_cell = self._escape_typst_text(cell)
                # Check if cell contains primarily numbers/currency/percentages
                if any(c in cell_content for c in ['$', '%', '€', '£']) or cell_content.replace(',', '').replace('.', '').replace('-', '').replace('+', '').replace('$', '').isdigit():
                    aligned_cells.append(f'[#align(right)[{escaped_cell}]]')
                else:
                    aligned_cells.append(f'[#align(left)[{escaped_cell}]]')
            row_cells = ', '.join(aligned_cells)
            table_rows.append(row_cells)
        
        # Combine all rows
        all_rows = [header_cells] + table_rows
        table_content = ',\n  '.join(all_rows)
        
        return f"""#table(
  columns: ({', '.join(['auto'] * col_count)}),
  stroke: 1pt + rgb("#b0b0b0"),
  fill: (x, y) => if y == 0 {{ rgb("#4A90E2") }} else if calc.odd(y) {{ rgb("#f7f8fa") }} else {{ white }},
  align: horizon,
  inset: 8pt,
  {table_content}
)"""
    
    def _convert_inline_formatting(self, text: str) -> str:
        """Convert inline markdown formatting to Typst"""
        import re
        
        # Bold: **text** or __text__ -> *text*
        text = re.sub(r'\*\*(.+?)\*\*', r'*\1*', text)
        text = re.sub(r'__(.+?)__', r'*\1*', text)
        
        # Italic: *text* or _text_ -> _text_
        text = re.sub(r'(?<!\*)\*([^*]+?)\*(?!\*)', r'_\1_', text)
        text = re.sub(r'(?<!_)_([^_]+?)_(?!_)', r'_\1_', text)
        
        # Inline code: `code` -> `code`
        text = re.sub(r'`([^`]+?)`', r'`\1`', text)
        
        # Links: [text](url) -> #link("url")[text]
        text = re.sub(r'\[([^\]]+?)\]\(([^)]+?)\)', r'#link("\2")[\1]', text)
        
        # Images: ![alt](url) -> #image("url")
        text = re.sub(r'!\[([^\]]*?)\]\(([^)]+?)\)', r'#image("\2")', text)
        
        # Strikethrough: ~~text~~ -> #strike[text]
        text = re.sub(r'~~(.+?)~~', r'#strike[\1]', text)
        
        return text
    
    def _escape_typst_text(self, text: str) -> str:
        """Escape special characters for Typst"""
        # Escape dollar signs which are math delimiters in Typst
        text = text.replace('$', r'\$')
        # Escape other special characters if needed
        text = text.replace('#', r'\#')
        text = text.replace('@', r'\@')
        return text
    
    def _get_template(self, template_name: str) -> str:
        """Get Typst template from file or inline"""
        template_dir = self.base_dir / "templates" / "typst"
        template_file = template_dir / f"{template_name}.typ"
        
        # Try to load from file first
        if template_file.exists():
            try:
                with open(template_file, 'r', encoding='utf-8') as f:
                    return f.read()
            except Exception as e:
                self.logger.warning(f"Failed to load template file {template_file}: {e}")
        
        # Fallback to inline templates
        return self._get_inline_template(template_name)
    
    def _get_inline_template(self, template_name: str) -> str:
        """Get fallback inline Typst template"""
        templates = {
            "technical": '''#set document(title: "{title}", author: "{author}")
#set page(
  paper: "a4",
  margin: (left: 2.5cm, right: 2.5cm, top: 2.5cm, bottom: 2.5cm),
  numbering: "1",
  number-align: center,
)

#set text(
  font: "New Computer Modern",
  size: 11pt,
  lang: "en"
)

#set heading(numbering: "1.1")
#set par(justify: true, leading: 0.65em)

#align(center)[
  #text(size: 20pt, weight: "bold")[{title}]
  
  #v(1em)
  
  #text(size: 12pt)[{author}]
  
  #v(0.5em)
  
  #text(size: 10pt)[{date}]
]

#v(2em)''',

            "academic": '''#set document(title: "{title}", author: "{author}")
#set page(
  paper: "a4", 
  margin: (left: 3cm, right: 3cm, top: 2.5cm, bottom: 2.5cm),
  numbering: "1",
  number-align: center,
)

#set text(
  font: "Linux Libertine",
  size: 12pt,
  lang: "en"
)

#set heading(numbering: "1.")
#set par(justify: true, first-line-indent: 1.5em)

#align(center)[
  #text(size: 18pt, weight: "bold")[{title}]
  
  #v(1em)
  
  #text(size: 14pt)[{author}]
  
  #v(0.5em)
  
  #text(size: 10pt)[{date}]
]

#v(2em)''',

            "minimal": '''#set document(title: "{title}", author: "{author}")
#set page(margin: 2cm, numbering: "1")
#set text(font: "Arial", size: 11pt)
#set heading(numbering: "1.")

#align(center)[
  #text(size: 16pt, weight: "bold")[{title}]
  #v(1em)
  #text(size: 10pt)[{author} • {date}]
]

#v(1.5em)''',

            "corporate": '''#set document(title: "{title}", author: "{author}")
#set page(
  paper: "a4",
  margin: (left: 2cm, right: 2cm, top: 2cm, bottom: 2cm),
  numbering: "1",
  number-align: center,
  header: [
    #line(length: 100%, stroke: 0.5pt + gray)
    #v(-8pt)
    #text(size: 8pt, fill: gray)[{title}]
    #h(1fr)
    #text(size: 8pt, fill: gray)[{date}]
  ]
)

#set text(font: "Arial", size: 11pt)
#set heading(numbering: "1.")
#set par(justify: true)

#align(center)[
  #text(size: 20pt, weight: "bold", fill: rgb("#1f4788"))[{title}]
  
  #v(0.5em)
  
  #text(size: 12pt, fill: gray)[{author}]
  
  #v(0.3em)
  
  #text(size: 10pt, fill: gray)[{date}]
]

#v(2em)''',

            "educational": '''#set document(title: "{title}", author: "{author}")
#set page(
  paper: "a4",
  margin: 2.5cm,
  numbering: "1",
  number-align: center,
)

#set text(font: "Open Sans", size: 11pt)
#set heading(numbering: "1.")
#set par(justify: true, leading: 0.7em)

#rect(
  width: 100%,
  fill: rgb("#f0f8ff"),
  stroke: rgb("#4a90e2"),
  radius: 5pt,
  inset: 1em
)[
  #align(center)[
    #text(size: 18pt, weight: "bold", fill: rgb("#2c5aa0"))[{title}]
    
    #v(0.5em)
    
    #text(size: 12pt)[{author}]
    
    #v(0.3em)
    
    #text(size: 10pt, style: "italic")[{date}]
  ]
]

#v(2em)'''
        }
        
        return templates.get(template_name, templates["technical"])
