"""Public key registration app."""

from enum import Enum
from typing import Annotated

import typer
from msgspec.json import encode as json_encode
from msgspec.yaml import encode as yaml_encode
from rich.table import Table
from slices_clientlib_core.base.exceptions import ApiException, NotFoundException

from slices_cli_core import console, err_console
from slices_cli_core.core.context import Context
from slices_cli_core.core.users_info import USER_ID_HELP
from slices_cli_core.util.errors import get_api_error_detail

pubkey_app = typer.Typer(name="pubkey", help="SSH key management", no_args_is_help=True)


@pubkey_app.command(name="register", rich_help_panel="Commands")
def register_pubkey(ctx: Context, file: Annotated[typer.FileText, typer.Argument]):
    """Register public key."""

    try:
        ctx.obj.api.public_key.register_for_user(
            ctx.obj.get_logged_in_userinfo("sub"),
            file.read(),
        )
        console.print("[bold green]Registered public key.[/] :white_check_mark:")
    except ApiException as err:
        err_console.print("[bold red]Could not register public key[/] :x:")
        err_console.print(f"[red]{get_api_error_detail(err)}")
        raise typer.Exit(code=1) from None


class Format(Enum):
    """Output format Options."""

    table = "table"
    text = "text"
    json = "json"
    yaml = "yaml"


def validate_user_id(ctx: typer.Context, value: str):
    """Validate user ID, resolving it if it is not a TypeID. Always return TypeID."""
    if value is None:
        return None
    return ctx.obj.other_users_info.resolve_project_member(ctx.obj.require_project_id(), value)


def _abbreviate_pubkey(pubkey: str) -> str:
    """Abbreviate public key for display."""
    if len(pubkey) <= 30:  # noqa: PLR2004
        return pubkey
    return f"{pubkey[:15]}...{pubkey[-15:]}"  # noqa: PLR2004


@pubkey_app.command(name="list", rich_help_panel="Commands")
def list_pubkeys(
    ctx: Context,
    user_id: Annotated[
        str | None, typer.Option(help=f"User ID to list public keys for. {USER_ID_HELP}", callback=validate_user_id)
    ] = None,
    fingerprint: Annotated[bool, typer.Option(help="Show pubkey fingerprint.")] = True,
    abbreviate_key: Annotated[bool, typer.Option(help="Show abbreviated pubkey instead of full key.")] = True,
    creation: Annotated[bool, typer.Option(help="Show when key was added.")] = True,
    format: Annotated[Format, typer.Option("--format", "-f", help="Output format.")] = "table",  # type: ignore
):
    """List registered public key."""
    is_local_user = not user_id
    if not user_id:
        user_id = ctx.obj.get_logged_in_userinfo("sub")

    pubkeys = ctx.obj.api.public_key.list_for_user(user_id)

    if format == Format.table:
        table_headers = ["ID"]
        if creation:
            table_headers.append("Created At")
        if fingerprint:
            table_headers.append("Fingerprint")
        table_headers.append("Public Key")
        table = Table(*table_headers)
        for pubkey in pubkeys:
            row_values = [str(pubkey.id)]
            if creation:
                row_values.append(str(pubkey.created_at))
            if fingerprint:
                row_values.append(pubkey.sha256_fingerprint)
            if not abbreviate_key:
                row_values.append(pubkey.public_key)
            else:
                row_values.append(_abbreviate_pubkey(pubkey.public_key))
            table.add_row(*row_values)

        if not is_local_user:
            user_info = ctx.obj.other_users_info.try_get_user_info_opt(user_id)
            console.print(f"Public keys for {user_id}")
            if user_info:
                console.print(
                    f"User details: {user_info.first_name} {user_info.last_name} - "
                    f"{user_info.email} - {user_info.preferred_username}"
                )
        console.print(table)
        console.print(f"{len(pubkeys)} public keys registered")
    elif format == Format.text:
        for pubkey in pubkeys:
            console.print(pubkey.public_key)
    elif format == Format.json:
        console.print_json(json_encode(list(pubkeys)).decode())
    elif format == Format.yaml:
        console.print(yaml_encode(list(pubkeys)).decode())


@pubkey_app.command(name="delete", rich_help_panel="Commands")
def delete_pubkey(ctx: Context, id: int):
    """Delete registered public key."""
    try:
        pubkey = ctx.obj.api.public_key.delete_by_id(id)

        console.print(f"Deleted key {pubkey.id} with fingerprint {pubkey.sha256_fingerprint}")
    except NotFoundException:
        err_console.print("[bold red]No public key with this ID. :x:")
