"""
CLI entry point for token-diet.
"""

from __future__ import annotations

import os
import sys
from typing import Optional

import click
from rich import print as rprint
from rich.columns import Columns
from rich.console import Console
from rich.panel import Panel
from rich.rule import Rule
from rich.text import Text

from token_diet.compressor import (
    MIN_TOKENS_TO_COMPRESS,
    Compressor,
    CompressionLevel,
    CompressionResult,
    count_tokens,
)

console = Console()
err_console = Console(stderr=True)


# ---------------------------------------------------------------------------
# Diff helper
# ---------------------------------------------------------------------------

def _show_diff(original: str, compressed: str) -> None:
    """Print a simple word-level diff using difflib."""
    import difflib

    original_lines = original.splitlines(keepends=True)
    compressed_lines = compressed.splitlines(keepends=True)

    diff = list(
        difflib.unified_diff(
            original_lines,
            compressed_lines,
            fromfile="original",
            tofile="compressed",
            lineterm="",
        )
    )

    if not diff:
        console.print("[dim]No differences.[/dim]")
        return

    for line in diff:
        if line.startswith("---") or line.startswith("+++"):
            console.print(f"[bold]{line}[/bold]")
        elif line.startswith("-"):
            console.print(f"[red]{line}[/red]")
        elif line.startswith("+"):
            console.print(f"[green]{line}[/green]")
        elif line.startswith("@@"):
            console.print(f"[cyan]{line}[/cyan]")
        else:
            console.print(f"[dim]{line}[/dim]")


# ---------------------------------------------------------------------------
# Rich report
# ---------------------------------------------------------------------------

def _print_report(result: CompressionResult, level: str, show_diff: bool) -> None:
    """Render the full Rich report to stdout."""
    # Header
    console.print(
        Panel.fit(
            "[bold white]TOKEN DIET REPORT[/bold white]",
            border_style="bold cyan",
            padding=(0, 12),
        )
    )
    console.print()

    mode_label = f"[bold yellow]{level}[/bold yellow] compression"
    if result.used_api:
        mode_label += " [dim](via Claude API)[/dim]"
    else:
        mode_label += " [dim](rule-based / offline)[/dim]"
    console.print(f"Mode: {mode_label}")
    console.print()

    # Already short?
    if result.original_tokens < MIN_TOKENS_TO_COMPRESS:
        console.print(
            Panel(
                "[bold green]Already under 50 tokens — nothing to compress.[/bold green]\n"
                f"Your prompt is only [bold]{result.original_tokens}[/bold] tokens.",
                border_style="green",
            )
        )
        return

    # Before
    console.print(Rule("[bold]BEFORE[/bold]", style="dim"))
    console.print(
        Panel(
            result.original_text,
            border_style="dim",
            padding=(0, 1),
        )
    )
    console.print()

    # After
    console.print(Rule("[bold]AFTER[/bold]", style="green"))
    console.print(
        Panel(
            result.compressed_text,
            border_style="green",
            padding=(0, 1),
        )
    )
    console.print()

    # Diff
    if show_diff:
        console.print(Rule("[bold]DIFF[/bold]", style="blue"))
        _show_diff(result.original_text, result.compressed_text)
        console.print()

    # Stats
    pct = result.percent_saved
    pct_color = "green" if pct >= 30 else ("yellow" if pct >= 10 else "red")

    cost = result.cost_saved_gpt4o
    cost_str = f"${cost:.4f}" if cost >= 0.0001 else f"${cost:.6f}"

    console.print(Rule("[bold]Results[/bold]", style="bold"))
    console.print(
        f"  Original:   [bold]{result.original_tokens}[/bold] tokens"
        f"  [dim](~{result.original_chars:,} chars)[/dim]"
    )
    console.print(
        f"  Compressed: [bold]{result.compressed_tokens}[/bold] tokens"
        f"  [dim](~{result.compressed_chars:,} chars)[/dim]"
    )
    console.print(
        f"  Saved:      [bold {pct_color}]{result.tokens_saved}[/bold {pct_color}] tokens"
        f"  [{pct_color}]({pct:.1f}% reduction)[/{pct_color}]"
    )
    console.print(
        f"  Est. savings: [bold cyan]{cost_str}/call[/bold cyan]"
        f"  [dim](at GPT-4o pricing $5/1M tokens)[/dim]"
    )
    console.print()

    # Techniques
    if result.techniques_applied:
        console.print(Rule("[bold]Techniques applied[/bold]", style="bold"))
        for technique in result.techniques_applied:
            console.print(f"  [dim]•[/dim] {technique}")
        console.print()


# ---------------------------------------------------------------------------
# CLI
# ---------------------------------------------------------------------------

@click.command(context_settings={"help_option_names": ["-h", "--help"]})
@click.argument("input_file", required=False, type=click.Path(exists=True, readable=True))
@click.option(
    "--api-key",
    envvar="ANTHROPIC_API_KEY",
    default=None,
    help="Anthropic API key. Also reads ANTHROPIC_API_KEY env var.",
    metavar="KEY",
)
@click.option(
    "--level",
    type=click.Choice(["gentle", "balanced", "aggressive"], case_sensitive=False),
    default="balanced",
    show_default=True,
    help="Compression aggressiveness.",
)
@click.option(
    "--diff",
    "show_diff",
    is_flag=True,
    default=False,
    help="Show a diff between original and compressed prompt.",
)
@click.option(
    "--quiet",
    "-q",
    is_flag=True,
    default=False,
    help="Output only the compressed text (for piping).",
)
@click.version_option(package_name="token-diet")
def main(
    input_file: Optional[str],
    api_key: Optional[str],
    level: str,
    show_diff: bool,
    quiet: bool,
) -> None:
    """Compress a prompt to use fewer tokens without losing meaning.

    INPUT_FILE is optional. If omitted, reads from stdin.

    Examples:

    \b
      token-diet prompt.txt
      echo "Please summarize this..." | token-diet
      token-diet prompt.txt --level aggressive --diff
      token-diet prompt.txt --quiet | pbcopy
    """
    # Read input
    if input_file:
        try:
            with open(input_file, "r", encoding="utf-8") as fh:
                text = fh.read()
        except OSError as exc:
            err_console.print(f"[red]Error reading file:[/red] {exc}")
            sys.exit(1)
    elif not sys.stdin.isatty():
        text = sys.stdin.read()
    else:
        err_console.print(
            "[red]Error:[/red] No input provided. "
            "Pass a file path or pipe text via stdin.\n"
            "Run [bold]token-diet --help[/bold] for usage."
        )
        sys.exit(1)

    text = text.strip()
    if not text:
        err_console.print("[red]Error:[/red] Input is empty.")
        sys.exit(1)

    # Validate API key hint
    if not api_key and not quiet:
        err_console.print(
            "[dim]No API key found — using offline rule-based compression. "
            "Set ANTHROPIC_API_KEY or pass --api-key to use Claude.[/dim]"
        )

    compression_level = CompressionLevel(level.lower())
    compressor = Compressor(api_key=api_key, level=compression_level)

    try:
        result = compressor.compress(text)
    except Exception as exc:  # pragma: no cover
        err_console.print(f"[red]Compression failed:[/red] {exc}")
        sys.exit(1)

    if quiet:
        # Raw output only — for piping
        click.echo(result.compressed_text)
        return

    _print_report(result, level, show_diff)


if __name__ == "__main__":
    main()
