"""The local package index — the always-available dependency source — and the
devpi endpoint resolver (the federation's ONE source for "which index?").

``release-local`` (Phase 2) builds a wheel, validates it, and **publishes it here**;
dependents in later waves then resolve their mgf-* deps from it without touching the
remote index. Same version number as the eventual remote (build-once): a local release
of ``vX`` is the identical artifact later *promoted* to devpi.

Resolution precedence (Q2): the local index (``--find-links``) alongside devpi, then
devpi's own pull-through cache for public deps. pip/uv pick the highest available
version across sources, so a locally-released version that is *ahead* of remote wins —
matching "local may lead; remote is the mirror".

devpi endpoint resolution (M2 §3.4, the PAPER-113 companion)
------------------------------------------------------------
``devpi_url()`` is the ONE resolver for the self-hosted index endpoint. Precedence:

1. ``$DEVPI_URL`` — the same variable Woodpecker injects server-level into every
   CI step (MGF_INFRA.md §2; value = the ``…/magogi/prod/+simple/`` endpoint).
2. the documented default below (MGF_INFRA.md §1; interim ``<ip>.sslip.io`` host).

Host-side consumers (release promotion, fleet-lock tooling) call the resolver;
*generated pipelines* never embed the resolved value — they reference the
``$DEVPI_URL`` variable itself with a fail-fast guard (see ``_woodpecker``), so a
devpi host move is: update the Woodpecker server variable + the default here, then
re-render the fleet — never a hand-search across committed pipelines.
"""

from __future__ import annotations

import os
import re
import shutil
from pathlib import Path

_WHEEL_RE = re.compile(r"^(?P<name>[A-Za-z0-9_.]+?)-(?P<ver>[0-9][^-]*)-.*\.whl$")

#: The Woodpecker server-level variable name (PAPER-113; coordinated with
#: sooth-standard). Generated pipelines reference it as ``$DEVPI_URL``.
DEVPI_URL_VAR = "DEVPI_URL"

# The MGF_INFRA.md §1 endpoint — the resolver's documented fallback and the ONLY
# place this literal lives in the repo. A devpi host/IP move updates the server
# variable + this default (+ MGF_INFRA's §1 row), then re-renders the fleet.
_DEVPI_URL_DEFAULT = "https://195.15.203.250.sslip.io/magogi/prod/+simple/"

PYPI_INDEX = "https://pypi.org/simple/"


def devpi_url() -> str:
    """The devpi index endpoint (``…/+simple/`` shape) — the ONE resolver (§3.4).

    Precedence: a non-empty ``$DEVPI_URL`` (the Woodpecker server-level variable,
    so host-side tooling and CI resolve the same fact from the same name) → the
    MGF_INFRA.md §1 default. Never raises, never blocks.
    """
    return os.environ.get(DEVPI_URL_VAR, "").strip() or _DEVPI_URL_DEFAULT


def local_index_dir() -> Path:
    d = Path.home() / ".mgf" / "local-index"
    d.mkdir(parents=True, exist_ok=True)
    return d


def list_local() -> dict[str, list[str]]:
    """``{normalized package name: sorted versions}`` currently in the local index."""
    out: dict[str, set[str]] = {}
    for whl in local_index_dir().glob("*.whl"):
        m = _WHEEL_RE.match(whl.name)
        if m:
            out.setdefault(m["name"].replace("_", "-").lower(), set()).add(m["ver"])
    return {k: sorted(v) for k, v in sorted(out.items())}


def resolve_args(*, local: bool = True, remote: bool = True) -> list[str]:
    """pip/uv resolution args.

    ``local`` adds the local index (``--find-links``). ``remote`` adds devpi
    (``devpi_url()``) as the SINGLE ``--index-url`` — no public-PyPI extra-index:
    magogi/prod serves mgf-* local-only and proxies public deps through its
    root/pypi pull-through cache, so one index resolves everything and
    dependency-confusion is structurally impossible (the fleet's no-extra-index
    law). With ``remote=False`` (the local-release smoke), devpi is omitted:
    mgf-* deps must resolve from the **local index** (third-party from public
    PyPI) — which enforces wave order, since a dependent can only smoke-install
    once its deps are locally released.
    """
    args: list[str] = []
    if local:
        args += ["--find-links", str(local_index_dir())]
    if remote:
        args += ["--index-url", devpi_url()]
    else:
        args += ["--index-url", PYPI_INDEX]
    return args


def publish(wheel: Path) -> Path:
    """Copy a built wheel into the local index (idempotent). Returns the destination."""
    dest = local_index_dir() / Path(wheel).name
    shutil.copy2(wheel, dest)
    return dest


def run_local_index() -> int:
    d = local_index_dir()
    pkgs = list_local()
    print(f"local index: {d}  ({len(pkgs)} packages)")
    for name, vers in pkgs.items():
        print(f"  {name:<24} {', '.join(vers)}")
    print(f"\nresolve order: local find-links → devpi ({devpi_url()})")
    print("(release-local publishes wheels here; dependents resolve from it first)")
    return 0
