"""
Highlighted content display for showing file changes with +/- indicators.
"""
import difflib
from typing import List, Optional
from rich.panel import Panel
from rich.text import Text
from rich.table import Table

class HighlightedContentDisplay:
    """Display file content with highlighted changes."""
    
    @staticmethod
    def get_language_from_path(file_path: str) -> str:
        """Determine programming language from file extension."""
        if file_path.endswith('.py'):
            return 'python'
        elif file_path.endswith('.js'):
            return 'javascript'
        elif file_path.endswith('.ts'):
            return 'typescript'
        elif file_path.endswith('.html'):
            return 'html'
        elif file_path.endswith('.css'):
            return 'css'
        elif file_path.endswith('.json'):
            return 'json'
        elif file_path.endswith('.xml'):
            return 'xml'
        elif file_path.endswith('.yaml') or file_path.endswith('.yml'):
            return 'yaml'
        elif file_path.endswith('.md'):
            return 'markdown'
        elif file_path.endswith('.sh'):
            return 'bash'
        elif file_path.endswith('.sql'):
            return 'sql'
        else:
            return 'text'
    
    @staticmethod
    def create_highlighted_file_content(
        content: str,
        file_path: str,
        changed_lines: Optional[List[int]] = None,
        added_lines: Optional[List[int]] = None,
        removed_lines: Optional[List[int]] = None,
        max_lines: int = 50
    ) -> Panel:
        """Create a panel showing file content with +/- indicators for changes."""

        lines = content.splitlines()
        language = HighlightedContentDisplay.get_language_from_path(file_path)

        # If content is too long, show first part with truncation notice
        display_lines = lines[:max_lines]
        is_truncated = len(lines) > max_lines

        # Create content with line numbers and +/- indicators
        content_text = Text()

        for i, line in enumerate(display_lines, 1):
            # Determine the change indicator and styles
            if added_lines and i in added_lines:
                indicator = "+"
                indicator_style = "bold green"
                line_style = "green"
                line_num_style = "green"
            elif removed_lines and i in removed_lines:
                indicator = "-"
                indicator_style = "bold red"
                line_style = "red"
                line_num_style = "red"
            elif changed_lines and i in changed_lines:
                indicator = "~"
                indicator_style = "bold yellow"
                line_style = "yellow"
                line_num_style = "yellow"
            else:
                indicator = " "
                indicator_style = "dim"
                line_style = "dim"
                line_num_style = "dim"

            # Line number with appropriate color
            content_text.append(f"{i:3d} ", style=line_num_style)
            # Indicator with appropriate color
            content_text.append(f"{indicator} ", style=indicator_style)

            # Line content with appropriate color
            content_text.append(line, style=line_style)
            content_text.append("\n")

        if is_truncated:
            content_text.append(f"\n... ({len(lines) - max_lines} more lines)", style="dim italic")

        return Panel(
            content_text,
            title=f"📄 {file_path}" + (" (with changes)" if changed_lines or added_lines or removed_lines else ""),
            title_align="left",
            border_style="green" if changed_lines or added_lines or removed_lines else "blue",
            padding=(0, 1)
        )
    
    @staticmethod
    def create_edit_result_display(
        old_content: str,
        new_content: str,
        old_text: str,
        new_text: str,
        file_path: str
    ) -> Panel:
        """Create a display for edit results showing both deleted (-) and added (+) lines."""

        # Create a unified diff view showing both old and new content
        old_lines = old_content.splitlines()
        new_lines = new_content.splitlines()

        # Use difflib to generate a proper unified diff
        diff_lines = list(difflib.unified_diff(
            old_lines, new_lines,
            fromfile=f"a/{file_path}", tofile=f"b/{file_path}",
            lineterm="", n=3
        ))

        # Convert unified diff to our display format
        content_text = Text()
        line_num = 0
        old_line_num = 0
        new_line_num = 0

        for line in diff_lines:
            if line.startswith('@@'):
                # Parse hunk header to get line numbers
                import re
                match = re.match(r'@@ -(\d+),?\d* \+(\d+),?\d* @@', line)
                if match:
                    old_line_num = int(match.group(1)) - 1
                    new_line_num = int(match.group(2)) - 1
                # Skip the @@ line in display
                continue
            elif line.startswith('---') or line.startswith('+++'):
                # Skip file headers
                continue
            elif line.startswith('-'):
                # Deleted line
                old_line_num += 1
                content_text.append(f"{old_line_num:3d} ", style="red")
                content_text.append("- ", style="bold red")
                content_text.append(line[1:], style="red")
                content_text.append("\n")
            elif line.startswith('+'):
                # Added line
                new_line_num += 1
                content_text.append(f"{new_line_num:3d} ", style="green")
                content_text.append("+ ", style="bold green")
                content_text.append(line[1:], style="green")
                content_text.append("\n")
            else:
                # Context line (unchanged)
                old_line_num += 1
                new_line_num += 1
                content_text.append(f"{new_line_num:3d} ", style="dim")
                content_text.append("  ", style="dim")
                content_text.append(line[1:] if line.startswith(' ') else line, style="dim")
                content_text.append("\n")

        return Panel(
            content_text,
            title=f"📝 {file_path} (edited)",
            title_align="left",
            border_style="yellow",
            padding=(0, 1)
        )
    
    @staticmethod
    def create_write_file_result_display(
        content: str,
        file_path: str,
        is_new_file: bool,
        old_content: Optional[str] = None
    ) -> Panel:
        """Create a display for write_file results with +/- indicators."""

        if is_new_file:
            # For new files, show all lines as added (+)
            lines_count = len(content.splitlines())
            added_lines = list(range(1, lines_count + 1))
            return HighlightedContentDisplay.create_highlighted_file_content(
                content, file_path, added_lines=added_lines
            )
        else:
            # For overwritten files, show diff-style indicators
            if old_content:
                # Find changed, added, and removed lines by comparing old and new content
                old_lines = old_content.splitlines()
                new_lines = content.splitlines()

                # Use difflib to find changes
                differ = difflib.SequenceMatcher(None, old_lines, new_lines)
                added_lines = []
                changed_lines = []

                for tag, i1, i2, j1, j2 in differ.get_opcodes():
                    if tag == 'replace':
                        # Check if it's a simple replacement or mixed
                        if (i2 - i1) == (j2 - j1):
                            # Same number of lines - mark as changed
                            for line_num in range(j1 + 1, j2 + 1):
                                changed_lines.append(line_num)
                        else:
                            # Different number of lines - some changed, some added
                            min_lines = min(i2 - i1, j2 - j1)
                            # First part is changed
                            for line_num in range(j1 + 1, j1 + min_lines + 1):
                                changed_lines.append(line_num)
                            # Rest is added
                            for line_num in range(j1 + min_lines + 1, j2 + 1):
                                added_lines.append(line_num)
                    elif tag == 'insert':
                        # Lines were added
                        for line_num in range(j1 + 1, j2 + 1):
                            added_lines.append(line_num)

                return HighlightedContentDisplay.create_highlighted_file_content(
                    content, file_path,
                    changed_lines=changed_lines,
                    added_lines=added_lines
                )
            else:
                # No old content available, show without indicators
                return HighlightedContentDisplay.create_highlighted_file_content(
                    content, file_path
                )
    
    @staticmethod
    def create_side_by_side_comparison(
        old_content: str,
        new_content: str,
        file_path: str,
        max_lines: int = 30
    ) -> Panel:
        """Create a side-by-side comparison of old and new content."""
        
        old_lines = old_content.splitlines()
        new_lines = new_content.splitlines()
        
        # Limit lines for display
        old_display = old_lines[:max_lines]
        new_display = new_lines[:max_lines]
        
        # Create table for side-by-side display
        table = Table(show_header=True, header_style="bold magenta")
        table.add_column("Before", style="red", width=50)
        table.add_column("After", style="green", width=50)
        
        max_display_lines = max(len(old_display), len(new_display))
        
        for i in range(max_display_lines):
            old_line = old_display[i] if i < len(old_display) else ""
            new_line = new_display[i] if i < len(new_display) else ""
            
            # Add line numbers
            old_text = f"{i+1:3d} │ {old_line}" if old_line else ""
            new_text = f"{i+1:3d} │ {new_line}" if new_line else ""
            
            table.add_row(old_text, new_text)
        
        # Add truncation notice if needed
        if len(old_lines) > max_lines or len(new_lines) > max_lines:
            table.add_row(
                f"... ({len(old_lines) - max_lines} more)" if len(old_lines) > max_lines else "",
                f"... ({len(new_lines) - max_lines} more)" if len(new_lines) > max_lines else ""
            )
        
        return Panel(
            table,
            title=f"📝 Comparison: {file_path}",
            title_align="left",
            border_style="blue",
            padding=(0, 1)
        )

def create_enhanced_tool_result_display(result_data: dict, tool_name: str) -> Panel:
    """Create enhanced display for tool results with highlighted content."""
    
    operation = result_data.get('operation')
    file_path = result_data.get('file_path', 'unknown')
    summary = result_data.get('summary', 'Operation completed')
    
    if operation == 'edit_file':
        # Show the new content with highlighted changes
        old_content = result_data.get('old_content', '')
        new_content = result_data.get('new_content', '')
        old_text = result_data.get('old_text', '')
        new_text = result_data.get('new_text', '')
        
        return HighlightedContentDisplay.create_edit_result_display(
            old_content, new_content, old_text, new_text, file_path
        )
    
    elif operation == 'write_file':
        # Show the file content with highlighting for changes
        content = result_data.get('content', '')
        old_content = result_data.get('old_content')
        is_new_file = result_data.get('is_new_file', False)
        
        return HighlightedContentDisplay.create_write_file_result_display(
            content, file_path, is_new_file, old_content
        )
    
    else:
        # Fallback for other operations
        return Panel(
            Text(summary),
            title=f"✓ {tool_name}",
            title_align="left",
            border_style="green",
            padding=(0, 1)
        )
