"""
bb_micro – thin Python wrapper around the `micro` terminal editor.

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

from __future__ import annotations

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

__version__ = "2.0.14"
_MICRO_VERSION = __version__

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

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


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


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


def _release_tarball_name() -> str:
    return f"micro-{_MICRO_VERSION}-{_os_name()}{_arch()}.tar.gz"


def _download_url() -> str:
    return (
        f"https://github.com/zyedidia/micro/releases/download"
        f"/v{_MICRO_VERSION}/{_release_tarball_name()}"
    )


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

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


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


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

    binary.parent.mkdir(parents=True, exist_ok=True)
    tarball_name = _release_tarball_name()
    url = _download_url()
    tmp_archive = binary.parent / tarball_name

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

    with tarfile.open(tmp_archive, "r:gz") as tar:
        for member in tar.getmembers():
            if member.name.endswith(_binary_name()):
                member.name = _binary_name()
                tar.extract(member, binary.parent)  # noqa: S202
                break

    tmp_archive.unlink(missing_ok=True)

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


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

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