"""
llmpm — LLM Package Manager
CLI entry point.
"""

from __future__ import annotations

import sys
import traceback

import click
from rich.console import Console
from rich.panel import Panel

from llmpm import __version__
from llmpm.commands.install import install
from llmpm.commands.list_cmd import info, list_models, uninstall
from llmpm.commands.push import push
from llmpm.commands.run_cmd import run_model
from llmpm.commands.serve_cmd import serve

console = Console()

HELP_TEXT = """\
[bold green]llmpm[/] [dim]—[/] LLM Package Manager

  Download, run, and share AI models from the command line.
  Models are sourced from [bold]HuggingFace Hub[/].

[bold]Usage:[/]

  [bold cyan]llmpm install[/] [dim]<repo_id>[/]  Download and install a model
  [bold cyan]llmpm run[/]     [dim]<repo_id>[/]  Run a model (interactive chat)
  [bold cyan]llmpm serve[/]   [dim]<repo_id>[/]  Serve model as HTTP API
  [bold cyan]llmpm push[/]    [dim]<repo_id>[/]  Upload a model to HuggingFace
  [bold cyan]llmpm list[/]               Show all installed models
  [bold cyan]llmpm info[/]    [dim]<repo_id>[/]  Show details about a model
  [bold cyan]llmpm uninstall[/] [dim]<repo_id>[/]  Uninstall a model

[bold]Examples:[/]

  [dim]# Install a GGUF model (interactive quantisation picker)[/]
  [bold]llmpm install bartowski/Llama-3.2-1B-Instruct-GGUF[/]

  [dim]# Install with a specific quantisation[/]
  [bold]llmpm install bartowski/Llama-3.2-1B-Instruct-GGUF --quant Q4_K_M[/]

  [dim]# Install a full Transformer model[/]
  [bold]llmpm install meta-llama/Llama-3.2-1B-Instruct[/]

  [dim]# Run a model in interactive chat[/]
  [bold]llmpm run bartowski/Llama-3.2-1B-Instruct-GGUF[/]

  [dim]# Single-turn inference[/]
  [bold]llmpm run bartowski/Llama-3.2-1B-Instruct-GGUF --prompt "Hello!"[/]

  [dim]# Serve a model as an HTTP API[/]
  [bold]llmpm serve bartowski/Llama-3.2-1B-Instruct-GGUF[/]

  [dim]# Push a model to HuggingFace[/]
  [bold]llmpm push my-org/my-fine-tune --path ./my-model[/]

[bold]Backends:[/]

  [blue]GGUF[/] models  → [bold]llama.cpp[/]
    (requires: pip install llama-cpp-python)
  Other models  → [bold]Transformers[/]
    (requires: pip install transformers torch)

[bold]Docs:[/] https://github.com/llmpm-dev/llmpm
"""


class LlpmGroup(click.Group):
    """Custom group that shows a branded help page."""

    def format_help(self, _ctx, _formatter):
        """Render branded help panel instead of default Click output."""
        console.print(Panel(
            HELP_TEXT,
            title=f"[bold green]llmpm[/] [dim]v{__version__}[/]",
            border_style="dim green",
            padding=(1, 3),
        ))

    def parse_args(self, ctx, args):
        """Allow bare `llmpm` (no args) to show help instead of erroring."""
        # Allow `llmpm` with no args to show help instead of error
        if not args:
            ctx.ensure_object(dict)
        return super().parse_args(ctx, args)


@click.group(cls=LlpmGroup, invoke_without_command=True)
@click.version_option(
    version=__version__,
    prog_name="llmpm",
    message="%(prog)s  %(version)s",
)
@click.pass_context
def main(ctx: click.Context) -> None:
    """llmpm — LLM Package Manager."""
    if ctx.invoked_subcommand is None:
        console.print(Panel(
            HELP_TEXT,
            title=f"[bold green]llmpm[/] [dim]v{__version__}[/]",
            border_style="dim green",
            padding=(1, 3),
        ))


# Register commands
main.add_command(install)
main.add_command(run_model, name="run")
main.add_command(serve)
main.add_command(push)
main.add_command(list_models, name="list")
main.add_command(info)
main.add_command(uninstall)


# ── Module entry point (python -m llmpm) ──────────────────────────────────────

def entry():
    """Wrapper that handles uncaught exceptions gracefully."""
    try:
        main(standalone_mode=False)  # pylint: disable=no-value-for-parameter
    except click.ClickException as exc:
        exc.show()
        sys.exit(exc.exit_code)
    except click.Abort:
        console.print("\n  [dim]Aborted.[/]\n")
        sys.exit(1)
    except SystemExit as exc:
        sys.exit(exc.code)
    except KeyboardInterrupt:
        console.print("\n  [dim]Interrupted.[/]\n")
        sys.exit(130)
    except Exception as exc:  # pylint: disable=broad-except
        console.print(f"\n  [bold red]error[/]  Unexpected error: {exc}\n")
        if "--debug" in sys.argv:
            traceback.print_exc()
        sys.exit(1)
