"""
bb_yaml – thin Python wrapper around the portable command-line
YAML/JSON/XML/CSV/TOML processor (like jq, but for YAML).

On first use the appropriate pre-built binary is downloaded from the
official GitHub release page and cached in ``~/.cache/5bb-yaml/``.
"""

from __future__ import annotations

import os
import platform
import stat
import subprocess
import sys
import urllib.request
from pathlib import Path

__version__ = "4.45.1"
_YQ_VERSION = __version__

# ---------------------------------------------------------------------------
# Platform detection helpers
# ---------------------------------------------------------------------------

def _arch() -> str:
    machine = platform.machine().lower()
    if machine in ("x86_64", "amd64"):
        return "amd64"
    if machine in ("i386", "i686"):
        return "386"
    if machine in ("aarch64", "arm64"):
        return "arm64"
    if machine.startswith("arm"):
        return "arm"
    return machine


def _os_name() -> str:
    system = platform.system().lower()
    if system == "darwin":
        return "darwin"
    if system == "windows":
        return "windows"
    return "linux"


def _binary_name() -> str:
    return "yq.exe" if platform.system().lower() == "windows" else "yq"


def _asset_name() -> str:
    suffix = ".exe" if platform.system().lower() == "windows" else ""
    return f"yq_{_os_name()}_{_arch()}{suffix}"


def _download_url() -> str:
    return (
        f"https://github.com/mikefarah/yq/releases/download"
        f"/v{_YQ_VERSION}/{_asset_name()}"
    )


# ---------------------------------------------------------------------------
# Binary management
# ---------------------------------------------------------------------------

def _cache_dir() -> Path:
    return Path(os.environ.get("BB_CACHE_DIR", Path.home() / ".cache")) / "5bb-yaml"


def _binary_path() -> Path:
    return _cache_dir() / _binary_name()


def ensure_binary() -> Path:
    """Return the path to the yq binary, downloading it if necessary."""
    binary = _binary_path()
    if binary.exists():
        return binary

    binary.parent.mkdir(parents=True, exist_ok=True)
    url = _download_url()

    print(f"[5bb-yaml] Downloading yamlquery v{_YQ_VERSION} …", file=sys.stderr)
    try:
        urllib.request.urlretrieve(url, binary)  # noqa: S310
    except Exception as exc:  # pragma: no cover
        raise SystemExit(
            f"[5bb-yaml] Failed to download {url}: {exc}"
        ) from exc

    # Ensure the binary is executable.
    binary.chmod(binary.stat().st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)
    return binary


# ---------------------------------------------------------------------------
# Help
# ---------------------------------------------------------------------------

def _show_help() -> None:
    from rich.console import Console
    from rich.panel import Panel
    from rich.table import Table
    from rich.text import Text

    console = Console()

    console.print(Panel.fit(
        f"[bold cyan]yamlquery[/] [dim]v{__version__}[/]\n"
        "[dim]A portable YAML / JSON / XML / CSV / TOML processor[/]",
        border_style="cyan",
    ))

    console.print("\n[bold]Usage[/]")
    console.print("  [cyan]yamlquery[/] [yellow]<expression>[/] [green][flags][/] [blue][file...][/]\n")

    console.print("[bold]Examples[/]")
    examples = [
        ("Read a field",            "yamlquery '.name' file.yaml"),
        ("Read nested field",       "yamlquery '.metadata.name' file.yaml"),
        ("Update in place",         "yamlquery -i '.version = \"2.0\"' file.yaml"),
        ("Output as JSON",          "yamlquery -o json '.' file.yaml"),
        ("Merge two files",         "yamlquery '. * load(\"b.yaml\")' a.yaml"),
        ("Read from stdin",         "cat file.yaml | yamlquery '.name'"),
        ("Multiple documents",      "yamlquery '.[].name' multi.yaml"),
        ("Pretty-print",            "yamlquery -P '.' file.yaml"),
    ]
    tbl = Table(show_header=False, box=None, padding=(0, 2))
    tbl.add_column(style="dim")
    tbl.add_column(style="green")
    for desc, cmd in examples:
        tbl.add_row(desc, cmd)
    console.print(tbl)

    console.print("\n[bold]Common flags[/]")
    flags = [
        ("-i, --inplace",           "Edit file in place"),
        ("-o, --output-format",     "Output format: yaml | json | props | csv | tsv | xml"),
        ("-P, --prettyPrint",       "Pretty-print output"),
        ("-e, --exit-status",       "Exit 1 if expression returns no results"),
        ("-n, --null-input",        "Don't read input; use 'null' as input"),
        ("-r, --raw-output",        "Print raw strings (no quotes)"),
        ("    --xml-attribute-prefix", "Prefix for XML attributes (default: +@)"),
        ("    --version",           "Print version and exit"),
        ("-h, --help",              "Show this help"),
    ]
    ftbl = Table(show_header=False, box=None, padding=(0, 2))
    ftbl.add_column(style="yellow", no_wrap=True)
    ftbl.add_column(style="dim")
    for flag, desc in flags:
        ftbl.add_row(flag, desc)
    console.print(ftbl)

    console.print(
        "\n[dim]Full documentation: https://mikefarah.gitbook.io/yq[/]\n"
    )


# ---------------------------------------------------------------------------
# Entry point
# ---------------------------------------------------------------------------

def run() -> None:
    """CLI entry point – delegates all arguments to the yamlquery binary."""
    args = sys.argv[1:]
    if not args or args[0] in ("-h", "--help"):
        _show_help()
        sys.exit(0)
    binary = ensure_binary()
    full_args = [str(binary)] + args
    if platform.system().lower() == "windows":
        sys.exit(subprocess.call(full_args))
    os.execv(str(binary), full_args)
