"""
Output formatting and TSV writing for wittrans.

SPDX-FileCopyrightText: 2024 Jiri Grönroos <jiri.gronroos@iki.fi>

SPDX-License-Identifier: LGPL-3.0-or-later
"""

import csv
import sys
from typing import List, Optional

from rich.console import Console
from rich.markup import escape
from rich.panel import Panel
from rich.table import Table

from .language import get_language_name
from .models import FileResult, SearchStatistics


def display_results(
    results: List[FileResult],
    search_term: str,
    lang_code: str,
    source_type: str,
    indicate: bool = False,
    directories_searched: int = 0,
    mo_files_found: int = 0,
) -> None:
    """
    Display search results in a formatted table.

    Args:
        results: List of FileResult items to display
        search_term: The original search term
        lang_code: Language code being searched
        source_type: Type of translation source (e.g. "System" or "Flatpak")
        indicate: Whether to indicate/highlight search term matches
        directories_searched: Number of directories searched
        mo_files_found: Number of .mo files found
    """
    language_name = get_language_name(lang_code)
    console = Console()
    total_matches = sum(len(matches) for _, matches in results)

    # Build statistics message
    stats_parts = []
    if directories_searched > 0:
        stats_parts.append(
            f"searched {directories_searched} {'directory' if directories_searched == 1 else 'directories'}"
        )
    if mo_files_found > 0:
        stats_parts.append(
            f"found {mo_files_found} .mo {'file' if mo_files_found == 1 else 'files'}"
        )

    stats_message = ", ".join(stats_parts) if stats_parts else ""

    if not results:
        message = f"[yellow]No matches found for:[/yellow] [bold red]'{escape(search_term)}'[/bold red] in {source_type} {language_name} translations"
        if stats_message:
            message += f"\n[dim]({stats_message})[/dim]"

        console.print(
            Panel(
                message,
                title=f"{source_type} Search Results",
                border_style="yellow",
            )
        )
        return

    message = f"[green]Found {total_matches} {'match' if total_matches == 1 else 'matches'} for:[/green] [bold red]'{escape(search_term)}'[/bold red] in {source_type} {language_name} translations"
    if stats_message:
        message += f"\n[dim]({stats_message})[/dim]"

    console.print(
        Panel(
            message,
            title=f"{source_type} Search Results",
            border_style="green",
        )
    )

    table = Table(title=f"{language_name} Translation Matches ({source_type})")
    table.add_column("File", style="cyan", no_wrap=True)
    table.add_column("Context", style="magenta")
    table.add_column("Original Text", style="green")
    table.add_column(f"{language_name} Translation", style="yellow")

    for file_path, matches in results:
        for original, translation, context in matches:
            context_escaped = escape(context) if context else ""

            # Apply highlighting only if enabled
            if indicate:
                search_term_lower = search_term.lower()

                if search_term_lower in original.lower():
                    original_highlighted = _highlight_text(original, search_term)
                else:
                    original_highlighted = escape(original)

                if search_term_lower in translation.lower():
                    translation_highlighted = _highlight_text(translation, search_term)
                else:
                    translation_highlighted = escape(translation)
            else:
                # No highlighting
                original_highlighted = escape(original)
                translation_highlighted = escape(translation)

            table.add_row(
                str(file_path),
                context_escaped,
                original_highlighted,
                translation_highlighted,
            )
    console.print(table)


def display_search_summary(
    search_term: str,
    statistics: SearchStatistics,
    lang_code: str,
) -> None:
    """
    Display a summary panel with overall search statistics.

    Args:
        search_term: The search term that was used
        statistics: Search statistics to display
        lang_code: Language code that was searched
    """
    language_name = get_language_name(lang_code)
    console = Console()

    # Summary message
    summary_parts = [
        f"Searched for [bold red]'{escape(search_term)}'[/bold red]",
        f"in {statistics.directories_searched} "
        f"{'directory' if statistics.directories_searched == 1 else 'directories'}",
        f"found {statistics.mo_files_found} .mo "
        f"{'file' if statistics.mo_files_found == 1 else 'files'} "
        f"in {language_name}",
        f"{statistics.total_matches} "
        f"{'match' if statistics.total_matches == 1 else 'matches'}",
        f"in {statistics.search_duration_seconds:.2f}s",
    ]

    summary_text = ", ".join(summary_parts)

    console.print("\n")  # Add spacing before summary
    console.print(
        Panel(
            f"[cyan]{summary_text}[/cyan]",
            title="[bold]Search Summary[/bold]",
            border_style="cyan",
        )
    )


def _highlight_text(text: str, search_term: str) -> str:
    """
    Highlight occurrences of search_term in text.

    Args:
        text: The original text
        search_term: The term to highlight (case-insensitive)

    Returns:
        Text with Rich markup highlighting applied (escaped)
    """
    result = []
    search_lower = search_term.lower()
    text_lower = text.lower()

    last_pos = 0
    pos = 0

    while pos < len(text):
        # Find next occurrence
        idx = text_lower.find(search_lower, pos)
        if idx == -1:
            # No more matches, append rest of text (escaped)
            result.append(escape(text[last_pos:]))
            break

        # Append text before match (escaped)
        if idx > last_pos:
            result.append(escape(text[last_pos:idx]))

        # Append highlighted match (escaped)
        match_text = text[idx : idx + len(search_term)]
        result.append(f"[bold reverse]{escape(match_text)}[/bold reverse]")

        # Move position forward
        last_pos = idx + len(search_term)
        pos = last_pos

    return "".join(result)


def write_tsv_output(
    results_by_category: dict,
    search_term: str,
    lang_code: str,
    output_file: str,
    statistics: Optional[SearchStatistics] = None,
    # statistics: SearchStatistics = None,
) -> None:
    """
    Write search results to a TSV file with UTF-8 encoding.

    Args:
        results_by_category: Dictionary containing results categorized by source type
        search_term: The original search term
        lang_code: Language code being searched
        output_file: Path to the output TSV file
        statistics: Optional search statistics to include in metadata comments
    """
    language_name = get_language_name(lang_code)

    try:
        with open(output_file, "w", newline="", encoding="utf-8-sig") as tsvfile:
            writer = csv.writer(
                tsvfile,
                delimiter="\t",
                quoting=csv.QUOTE_MINIMAL,
                lineterminator="\n",
            )

            # Write metadata into TSV file as comments
            # RFC4180 does not specify how to present comments - use de facto comment
            if statistics:
                tsvfile.write(f"# Search term: {search_term}\n")
                tsvfile.write(f"# Language: {language_name} ({lang_code})\n")
                tsvfile.write(
                    f"# Directories searched: {statistics.directories_searched}\n"
                )
                tsvfile.write(f"# .mo files found: {statistics.mo_files_found}\n")
                tsvfile.write(f"# Total matches: {statistics.total_matches}\n")
                tsvfile.write(
                    f"# Search duration: {statistics.search_duration_seconds:.2f} seconds\n"
                )
                tsvfile.write("#\n")

            # Write header column names
            writer.writerow(
                [
                    "Source Type",
                    "File Path",
                    "Context",
                    "Original Text",
                    f"{language_name} Translation",
                ]
            )

            def safe_text(text: str) -> str:
                """Ensure text is properly encoded and handle any problematic characters."""
                if not text:
                    return ""
                return text.replace("\x00", "").strip()

            # Write results for each category
            for _category_key, category_data in results_by_category.items():
                source_type = category_data["display_name"]
                category_results = category_data["results"]

                for file_path, matches in category_results:
                    for original, translation, context in matches:
                        writer.writerow(
                            [
                                source_type,
                                str(file_path),
                                safe_text(context) if context else "",
                                safe_text(original),
                                safe_text(translation),
                            ]
                        )

    except UnicodeEncodeError as e:
        console = Console()
        console.print(
            Panel(
                f"Unicode encoding error writing to file '{output_file}': {str(e)}\n"
                "Some characters could not be encoded. Try using a different filename or check the translation data.",
                title="[red]Error: Unicode Encoding Failed[/red]",
                border_style="red",
            )
        )
        sys.exit(1)
    except IOError as e:
        console = Console()
        console.print(
            Panel(
                f"Error writing to file '{output_file}': {str(e)}",
                title="[red]Error: File Write Failed[/red]",
                border_style="red",
            )
        )
        sys.exit(1)
