"""Command-line interface for semantic text alignment."""

import asyncio
import sys
from pathlib import Path
from typing import Optional, Tuple

import typer
from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from rich.text import Text
from rich.progress import Progress, SpinnerColumn, TextColumn

from .core import AlignmentPair, SemanticAligner, AlignmentResult
from .utils import read_text_file, validate_file_path, sanitize_text, estimate_processing_time

app = typer.Typer(
    name="semantic-compare",
    help="Advanced text alignment and semantic containment analysis",
    add_completion=False,
)
console = Console()


def print_alignment_results(result: AlignmentResult) -> None:
    """Display alignment results in a rich, formatted way."""
    console.print("\n")
    
    # Create main results table
    table = Table(title="Semantic Alignment Results", show_header=True, header_style="bold magenta")
    table.add_column("Type", style="cyan", no_wrap=True)
    table.add_column("Text A", style="green")
    table.add_column("Text B", style="blue")
    table.add_column("Score", style="yellow", justify="right")
    
    for pair in result.pairs:
        if pair.type == "match":
            score_text = f"{pair.score:.3f}" if pair.score is not None else "N/A"
            table.add_row(
                f"[green]✓ Match[/green]",
                pair.text_a or "",
                pair.text_b or "",
                score_text
            )
        elif pair.type == "gap_b":
            table.add_row(
                "[yellow]⚠ Only in A[/yellow]",
                pair.text_a or "",
                "[dim]-[/dim]",
                "[dim]N/A[/dim]"
            )
        elif pair.type == "gap_a":
            table.add_row(
                "[yellow]⚠ Only in B[/yellow]",
                "[dim]-[/dim]",
                pair.text_b or "",
                "[dim]N/A[/dim]"
            )
        elif pair.type == "unaligned_a":
            table.add_row(
                "[red]✗ Unaligned A[/red]",
                pair.text_a or "",
                "[dim]-[/dim]",
                "[dim]N/A[/dim]"
            )
        elif pair.type == "unaligned_b":
            table.add_row(
                "[red]✗ Unaligned B[/red]",
                "[dim]-[/dim]",
                pair.text_b or "",
                "[dim]N/A[/dim]"
            )
    
    console.print(table)
    
    # Create statistics panel
    stats_text = Text()
    stats_text.append(f"Total paragraphs in A: {result.total_paragraphs_a}\n", style="green")
    stats_text.append(f"Total paragraphs in B: {result.total_paragraphs_b}\n", style="blue")
    stats_text.append(f"Matched pairs: {result.matched_pairs}\n", style="green")
    stats_text.append(f"Gap pairs: {result.gap_pairs}\n", style="yellow")
    stats_text.append(f"Unaligned pairs: {result.unaligned_pairs}\n", style="red")
    
    # Highlight containment score
    score_style = "green" if result.containment_score > 0.7 else "yellow" if result.containment_score > 0.4 else "red"
    stats_text.append(f"Semantic containment score: {result.containment_score:.2%}", style=score_style)
    
    stats_panel = Panel(
        stats_text,
        title="[bold]Analysis Statistics[/bold]",
        border_style="blue"
    )
    console.print(stats_panel)
    
    # Add explanation
    explanation = Panel(
        "The semantic containment score measures how much of text A's semantic content "
        "is found in text B. Higher scores indicate greater semantic overlap.",
        title="[bold]About the Score[/bold]",
        border_style="dim"
    )
    console.print(explanation)


async def _align_texts(
    text_a: str,
    text_b: str,
    model_name: str,
    gap_penalty: float,
    similarity_threshold: float
) -> AlignmentResult:
    """Internal async function to perform text alignment."""
    aligner = SemanticAligner(
        model_name=model_name,
        gap_penalty=gap_penalty,
        similarity_threshold=similarity_threshold
    )
    return await aligner.align_texts(text_a, text_b)


@app.command()
def compare(
    text_a: str = typer.Argument(..., help="First text to compare (or file path starting with @)"),
    text_b: str = typer.Argument(..., help="Second text to compare (or file path starting with @)"),
    model: str = typer.Option(
        "all-MiniLM-L6-v2",
        "--model",
        "-m",
        help="Sentence transformer model to use"
    ),
    gap_penalty: float = typer.Option(
        0.3,
        "--gap-penalty",
        "-g",
        help="Penalty for gaps in alignment (0.0-1.0)"
    ),
    similarity_threshold: float = typer.Option(
        0.5,
        "--similarity-threshold",
        "-t",
        help="Minimum similarity score for matches (0.0-1.0)"
    ),
    output_file: Optional[Path] = typer.Option(
        None,
        "--output",
        "-o",
        help="Output file for detailed results (JSON format)"
    ),
    quiet: bool = typer.Option(
        False,
        "--quiet",
        "-q",
        help="Suppress detailed output, show only summary"
    )
) -> None:
    """
    Compare two texts using semantic alignment.
    
    This command performs advanced semantic analysis between two texts,
    identifying matching paragraphs, gaps, and calculating containment scores.
    """
    # Validate parameters
    if not (0.0 <= gap_penalty <= 1.0):
        console.print("[red]Error: Gap penalty must be between 0.0 and 1.0[/red]")
        raise typer.Exit(1)
    
    if not (0.0 <= similarity_threshold <= 1.0):
        console.print("[red]Error: Similarity threshold must be between 0.0 and 1.0[/red]")
        raise typer.Exit(1)
    
    # Handle file inputs
    async def load_texts() -> Tuple[str, str]:
        """Load texts from arguments or files."""
        text_a_content = text_a
        text_b_content = text_b
        
        # Check if inputs are file paths
        if text_a.startswith('@'):
            file_path = Path(text_a[1:])
            if not validate_file_path(file_path):
                raise typer.Exit(1)
            text_a_content = await read_text_file(file_path)
            text_a_content = sanitize_text(text_a_content)
            console.print(f"[green]Loaded text A from: {file_path}[/green]")
        
        if text_b.startswith('@'):
            file_path = Path(text_b[1:])
            if not validate_file_path(file_path):
                raise typer.Exit(1)
            text_b_content = await read_text_file(file_path)
            text_b_content = sanitize_text(text_b_content)
            console.print(f"[green]Loaded text B from: {file_path}[/green]")
        
        return text_a_content, text_b_content
    
    # Show configuration
    if not quiet:
        console.print(Panel(
            f"Model: {model}\n"
            f"Gap penalty: {gap_penalty}\n"
            f"Similarity threshold: {similarity_threshold}",
            title="[bold]Configuration[/bold]",
            border_style="green"
        ))
    
    try:
        # Load texts
        text_a_content, text_b_content = asyncio.run(load_texts())
        
        # Estimate processing time
        if not quiet:
            estimated_time = estimate_processing_time(text_a_content, text_b_content)
            console.print(f"[blue]Estimated processing time: {estimated_time:.1f} seconds[/blue]")
        
        # Perform alignment with progress indicator
        with Progress(
            SpinnerColumn(),
            TextColumn("[progress.description]{task.description}"),
            console=console,
            transient=True
        ) as progress:
            task = progress.add_task("Performing semantic alignment...", total=None)
            result = asyncio.run(_align_texts(
                text_a_content, text_b_content, model, gap_penalty, similarity_threshold
            ))
            progress.update(task, completed=True)
        
        # Display results
        if not quiet:
            print_alignment_results(result)
        else:
            # Quiet mode - just show score
            score_style = "green" if result.containment_score > 0.7 else "yellow" if result.containment_score > 0.4 else "red"
            console.print(f"Containment score: [{score_style}]{result.containment_score:.2%}[/{score_style}]")
        
        # Save to file if requested
        if output_file:
            import json
            from dataclasses import asdict
            
            output_data = {
                "configuration": {
                    "model": model,
                    "gap_penalty": gap_penalty,
                    "similarity_threshold": similarity_threshold
                },
                "statistics": {
                    "total_paragraphs_a": result.total_paragraphs_a,
                    "total_paragraphs_b": result.total_paragraphs_b,
                    "matched_pairs": result.matched_pairs,
                    "gap_pairs": result.gap_pairs,
                    "unaligned_pairs": result.unaligned_pairs,
                    "containment_score": result.containment_score
                },
                "alignment_pairs": [asdict(pair) for pair in result.pairs]
            }
            
            with open(output_file, 'w', encoding='utf-8') as f:
                json.dump(output_data, f, indent=2, ensure_ascii=False)
            
            console.print(f"[green]Results saved to: {output_file}[/green]")
            
    except Exception as e:
        console.print(f"[red]Error during alignment: {e}[/red]")
        if not quiet:
            console.print_exception()
        raise typer.Exit(1)


@app.command()
def version() -> None:
    """Show version information."""
    from . import __version__
    console.print(f"semantic-compare version {__version__}")


if __name__ == "__main__":
    app() 