#!python
# SPDX-FileCopyrightText: 2024-2026 Daniel J. Mazure
# SPDX-License-Identifier: MIT
"""rr / routertl / routertl-mcp — RouteRTL CLI entry points (RTL-P3.307).

Shipped as standalone scripts (via setuptools ``scripts=``) instead of being
generated from ``[project.scripts]`` so that an opaque ``ModuleNotFoundError``
from an orphaned editable install (worktree at recorded path was deleted)
becomes an actionable error message pointing at the repair commands.

The auto-generated console-script template imports the entry-point at module
load time. When the editable install path is gone, that import fails before
any RouteRTL code can run — leaving the user staring at a stack trace with
no hint that ``pip install -e <new path>`` is the fix.
"""
from __future__ import annotations

import os
import sys

# ── Orphaned-editable detection (RTL-P2.702) ─────────────────────────────────
# This launcher runs in the BROKEN-import context, so it must stay import-safe:
# pure stdlib, never `import sdk`. The richer, reachable-while-healthy version
# lives in `sdk/cli/editable_health.py` (powers `rr doctor`); these helpers are
# the deliberately-duplicated minimal core. Keep the two in sync.


def _looks_like_sdk_root(path: str) -> bool:
    return os.path.exists(os.path.join(path, "VERSION")) or os.path.isdir(
        os.path.join(path, "sdk", "cli")
    )


def _is_git_worktree(path: str) -> bool:
    """True iff *path* is a linked git worktree (gitdir under ``worktrees/``).

    A submodule checkout also uses a ``.git`` file (gitdir under ``modules/``)
    but is stable — it must NOT be treated as a fragile worktree. Mirrors
    ``sdk/cli/editable_health.is_git_worktree``.
    """
    gitfile = os.path.join(path, ".git")
    if not os.path.isfile(gitfile):
        return False
    try:
        with open(gitfile, encoding="utf-8", errors="replace") as fh:
            content = fh.read().strip()
    except OSError:
        return False
    if not content.startswith("gitdir:"):
        return False
    gitdir = content.split(":", 1)[1].strip().replace("\\", "/")
    return "worktrees" in gitdir.split("/")


def _recorded_editable_paths() -> list[str]:
    """Source paths the routertl editable install is recorded against.

    Reads PEP 610 ``direct_url.json`` (what ``pip install -e`` writes) plus any
    bare-path ``.pth`` line that points at a routertl tree. Reading metadata
    does NOT import the (broken) package.
    """
    import glob
    import importlib.metadata as im
    import json
    import site
    from urllib.parse import unquote, urlparse

    paths: list[str] = []
    try:
        raw = im.distribution("routertl").read_text("direct_url.json")
    except Exception:
        raw = None
    if raw:
        try:
            info = json.loads(raw)
        except ValueError:
            info = {}
        if isinstance(info, dict) and info.get("dir_info", {}).get("editable"):
            url = info.get("url", "")
            if url.startswith("file:"):
                p = unquote(urlparse(url).path)
                if p:
                    paths.append(p)
    site_dirs: list[str] = []
    for getter in (site.getsitepackages, lambda: [site.getusersitepackages()]):
        try:
            site_dirs.extend(getter())
        except Exception:
            continue
    for sp in site_dirs:
        for pth in glob.glob(os.path.join(sp, "*.pth")):
            try:
                with open(pth, encoding="utf-8", errors="replace") as fh:
                    lines = fh.read().splitlines()
            except OSError:
                continue
            for line in lines:
                line = line.strip()
                if not line or line.startswith(("#", "import ")):
                    continue
                if os.path.basename(line) in {"routertl", "rapidrtl"} or (
                    _looks_like_sdk_root(line)
                ):
                    paths.append(line)
    # de-dup, preserve order
    seen: set[str] = set()
    out: list[str] = []
    for p in paths:
        if p not in seen:
            seen.add(p)
            out.append(p)
    return out


def _find_canonical_checkout(start: str) -> str | None:
    """Walk up from a dead source path to a live canonical sibling checkout."""
    start = os.path.abspath(start)
    fallback = None
    cur = start
    for _ in range(10):
        parent = os.path.dirname(cur)
        if parent == cur:
            break
        for cand in (os.path.join(parent, "routertl"), parent):
            if cand == start or not os.path.isdir(cand) or not _looks_like_sdk_root(cand):
                continue
            if not _is_git_worktree(cand):
                return cand  # primary checkout / submodule — best answer
            fallback = fallback or cand
        cur = parent
    return fallback


def _emit_orphan_install_error(exc: ModuleNotFoundError) -> None:
    prog = os.path.basename(sys.argv[0]) or "rr"
    out = [f"\n{prog}: cannot import RouteRTL — the install is broken.\n"]
    dead = [p for p in _recorded_editable_paths() if not os.path.isdir(p)]
    canonical = None
    for d in dead:
        canonical = _find_canonical_checkout(d)
        if canonical:
            break
    if dead:
        out.append(
            "  Orphaned editable install: the recorded source path was deleted\n"
            "  (common after a `pip install -e <worktree>` whose worktree is gone):\n"
        )
        for d in dead:
            out.append(f"    {d}   (missing)\n")
        out.append("\n  Repair:\n")
        if canonical:
            out.append(
                f"    pip install -e {canonical}"
                "   # re-link to your canonical checkout\n"
            )
        else:
            out.append(
                "    pip install -e /path/to/routertl   # re-link an existing checkout\n"
            )
        out.append(
            "    pip install --upgrade routertl         # or reinstall from PyPI\n"
        )
    else:
        out.append(
            "  The most common cause is an orphaned editable install: an earlier\n"
            "  `pip install -e <path>` is still recorded, but the worktree at\n"
            "  <path> has been deleted (common in multi-worktree workflows).\n\n"
            "  Repair:\n"
            "    pip install -e /path/to/routertl       # re-link an existing checkout\n"
            "    pip install --upgrade routertl         # or reinstall from PyPI\n"
        )
    out.append(
        "\n  Diagnose:\n"
        "    pip show routertl                      # confirms the recorded path\n"
        "    pip install --force-reinstall routertl # nuke and start fresh\n"
        f"\n  (original error: {exc})\n"
    )
    sys.stderr.write("".join(out))


def _is_routertl_install_failure(exc: ModuleNotFoundError) -> bool:
    """True iff the import failure is due to a missing RouteRTL package
    (not a missing user dep)."""
    name = exc.name or ""
    root = name.split(".")[0]
    return root in {"sdk", "routertl_core", "routertl"}


def _entry_module() -> str:
    """Map argv[0] basename → entry point module:function string.

    Matches the legacy ``[project.scripts]`` mapping so the published
    surface stays identical.
    """
    prog = os.path.basename(sys.argv[0]).removesuffix(".exe")
    if prog == "routertl-mcp":
        return "sdk.mcp_server:run"
    # rr, routertl, and any other alias all dispatch to the main CLI
    return "sdk.cli.main:cli"


def _main() -> int:
    target = _entry_module()
    module_name, _, attr = target.partition(":")
    try:
        mod = __import__(module_name, fromlist=[attr])
        fn = getattr(mod, attr)
    except ModuleNotFoundError as exc:
        if _is_routertl_install_failure(exc):
            _emit_orphan_install_error(exc)
            return 2
        raise
    rc = fn()
    return int(rc) if rc is not None else 0


if __name__ == "__main__":
    sys.exit(_main())
