import json
from importlib.metadata import PackageNotFoundError, distribution
from typing import Optional

from packaging.version import Version


def get_local_package_version(package_name="abstra"):
    try:
        return parse_version(distribution(package_name).version)
    except PackageNotFoundError:
        raise


def parse_version(version: str):
    return Version(version)


def get_local_package_direct_url(package_name="abstra") -> Optional[str]:
    """URL the package was pip-installed from (PEP 610 direct_url.json).

    Returns None when the package came from an index (PyPI), from a local
    directory, or from any source that `pip install <url>` couldn't reproduce:
    only remote archive installs qualify — local dirs record file:// with
    dir_info instead of archive_info, and VCS installs need their vcs prefix.
    """
    try:
        # filename passed by keyword: importlib.metadata's read_text takes a
        # filename (not encoding), and tests/test_encoding.py flags a positional
        # arg here as a non-utf-8 encoding.
        text = distribution(package_name).read_text(filename="direct_url.json")
    except PackageNotFoundError:
        return None
    if not text:
        return None
    try:
        data = json.loads(text)
    except json.JSONDecodeError:
        return None
    url = data.get("url")
    if (
        not isinstance(url, str)
        or "archive_info" not in data
        or not url.startswith(("https://", "http://"))
    ):
        return None
    return url


def _capture_running_version() -> Optional[str]:
    try:
        return str(get_local_package_version("abstra"))
    except PackageNotFoundError:
        return None


def _capture_running_direct_url() -> Optional[str]:
    try:
        return get_local_package_direct_url("abstra")
    except Exception:
        return None


# importlib.metadata reads dist-info from DISK, so after an in-place
# `pip install --upgrade` it reports the new version while this process still
# runs the old code. Captured at import (process boot) so it identifies the
# code actually running.
#
# None means abstra's own metadata could not be located at boot (e.g. running
# from source without dist-info). Consumers must treat None as "unknown" — note
# that "0.0.0" is a legitimate dev/CI version, NOT a not-found marker.
RUNNING_ABSTRA_VERSION: Optional[str] = _capture_running_version()

# Same boot-capture rationale as above: after a slot flip or in-place upgrade,
# the on-disk dist-info describes the new install, not the code this process
# is running. None means the running install has no reproducible source URL
# (index install, local dir, or no dist-info at all).
RUNNING_ABSTRA_DIRECT_URL: Optional[str] = _capture_running_direct_url()
