"""Secret commands for manta-client CLI."""

from __future__ import annotations

import asyncio
import sys
from typing import Any

import typer

from manta_client.api.agent.secret import get_secret_api
from manta_client.api.client import APIError
from manta_client.exitcodes import VALIDATION_ERROR, exit_code_for_api_error
from manta_client.output import (
    console,
    is_quiet,
    print_error,
    print_json,
    print_key_value,
    print_success,
    print_table,
)

app = typer.Typer(help="Secret management")


def _read_sensitive_value(
    flag_value: str | None,
    stdin_flag: bool,
    prompt_label: str,
    *,
    required: bool = True,
) -> str | None:
    """Read a sensitive value from flag, stdin, or interactive prompt.

    Priority: --value > --value-stdin (pipe) > interactive prompt (TTY only).
    """
    if flag_value is not None:
        return flag_value

    if stdin_flag:
        value = sys.stdin.read().strip()
        if not value and required:
            print_error(f"No {prompt_label} provided via stdin")
            raise typer.Exit(VALIDATION_ERROR)
        return value or None

    if required:
        # Interactive prompt — only if TTY
        if sys.stdin.isatty():
            import getpass

            value = getpass.getpass(f"{prompt_label}: ")
            if not value:
                print_error(f"{prompt_label} cannot be empty")
                raise typer.Exit(VALIDATION_ERROR)
            return value

        print_error(
            f"No {prompt_label} provided. Use --value <val> or --value-stdin "
            "(echo 'val' | manta-client ...)"
        )
        raise typer.Exit(VALIDATION_ERROR)

    return None


@app.command("list")
def list_secrets(
    limit: int = typer.Option(20, "--limit", "-l", help="Max results"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """List your secrets (values are never shown)."""

    async def _list():
        api = get_secret_api()
        return await api.list_secrets(scope="user", limit=limit)

    try:
        result = asyncio.run(_list())
    except APIError as e:
        print_error(e.message)
        raise typer.Exit(exit_code_for_api_error(e.code)) from None

    items = result.get("items", [])
    total = result.get("total", 0)

    if json_output:
        print_json(result)
        return

    if not items:
        if not is_quiet():
            console.print("[dim]No secrets found.[/dim]")
        return

    if is_quiet():
        for item in items:
            print(f"{item.get('id')}\t{item.get('name')}")
        return

    columns = [
        ("id", "ID"),
        ("name", "Name"),
        ("description", "Description"),
        ("created_at", "Created"),
    ]
    print_table(items, columns=columns, title=f"Secrets ({total})")


@app.command("create")
def create_secret(
    name: str = typer.Option(..., "--name", "-n", help="Unique secret name"),
    value: str = typer.Option(
        None, "--value", "-v", help="Secret value (omit for interactive prompt)"
    ),
    value_stdin: bool = typer.Option(
        False, "--value-stdin", help="Read value from stdin (for piping)"
    ),
    description: str = typer.Option(None, "--description", "-d", help="Secret description"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """Create a new secret (value is encrypted server-side).

    All secrets created via CLI are user-scoped (only injected into your jobs).

    Value can be provided via:
      --value <val>                 Direct value
      --value-stdin                 Read from stdin (echo 'val' | manta-client ...)
      (omit both)                   Interactive secure prompt (TTY only)
    """
    resolved_value = _read_sensitive_value(value, value_stdin, "Secret value")

    async def _create():
        api = get_secret_api()
        return await api.create_secret(
            name=name,
            value=resolved_value,
            description=description,
            scope="user",
        )

    try:
        result = asyncio.run(_create())
    except APIError as e:
        print_error(e.message)
        raise typer.Exit(exit_code_for_api_error(e.code)) from None

    if json_output:
        print_json(result)
    elif is_quiet():
        print(result.get("id", ""))
    else:
        print_success(f"Secret created: {result.get('name')} (ID: {result.get('id')})")


@app.command("info")
def secret_info(
    pk: int = typer.Argument(..., help="Secret ID"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """Show secret details (value is never shown)."""

    async def _get():
        api = get_secret_api()
        return await api.get_secret(pk)

    try:
        secret = asyncio.run(_get())
    except APIError as e:
        print_error(e.message)
        raise typer.Exit(exit_code_for_api_error(e.code)) from None

    if json_output:
        print_json(secret)
        return

    if is_quiet():
        print(f"{secret.get('id')}\t{secret.get('name')}")
        return

    data: dict[str, Any] = {
        "ID": secret.get("id"),
        "Name": secret.get("name"),
        "Description": secret.get("description") or "-",
        "Created At": secret.get("created_at") or "-",
        "Updated At": secret.get("updated_at") or "-",
    }
    print_key_value(data, title="Secret Details")


@app.command("update")
def update_secret(
    pk: int = typer.Argument(..., help="Secret ID"),
    value: str = typer.Option(None, "--value", "-v", help="New secret value"),
    value_stdin: bool = typer.Option(
        False, "--value-stdin", help="Read value from stdin (for piping)"
    ),
    description: str = typer.Option(None, "--description", "-d", help="New description"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """Update a secret."""
    resolved_value = _read_sensitive_value(value, value_stdin, "Secret value", required=False)

    async def _update():
        api = get_secret_api()
        return await api.update_secret(
            pk=pk,
            value=resolved_value,
            description=description,
        )

    try:
        result = asyncio.run(_update())
    except APIError as e:
        print_error(e.message)
        raise typer.Exit(exit_code_for_api_error(e.code)) from None

    if json_output:
        print_json(result)
    elif is_quiet():
        print(pk)
    else:
        print_success(f"Secret {pk} updated.")


@app.command("delete")
def delete_secret(
    pk: int = typer.Argument(..., help="Secret ID"),
) -> None:
    """Delete a secret."""

    async def _delete():
        api = get_secret_api()
        return await api.delete_secret(pk)

    try:
        asyncio.run(_delete())
        if is_quiet():
            print("deleted")
        else:
            print_success(f"Secret {pk} deleted.")
    except APIError as e:
        print_error(e.message)
        raise typer.Exit(exit_code_for_api_error(e.code)) from None
