import configparser
import os
import pathlib


def get_dirs() -> dict[str, pathlib.Path]:
    """Returns a dict of all the known XDG Base Directories for the current user.

    The keys ``XDG_CACHE_DIR``, ``XDG_CONFIG_DIR``, and ``XDG_DATA_DIR`` is
    always available.

    Additional keys, like ``XDG_MUSIC_DIR``, may be available if the
    ``$XDG_CONFIG_DIR/user-dirs.dirs`` file exists and is parseable.

    See http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
    for the XDG Base Directory specification.
    """

    dirs = {
        "XDG_CACHE_DIR": pathlib.Path(
            os.getenv("XDG_CACHE_HOME", "~/.cache"),
        ).expanduser(),
        "XDG_CONFIG_DIR": pathlib.Path(
            os.getenv("XDG_CONFIG_HOME", "~/.config"),
        ).expanduser(),
        "XDG_DATA_DIR": pathlib.Path(
            os.getenv("XDG_DATA_HOME", "~/.local/share"),
        ).expanduser(),
    }

    dirs.update(_get_user_dirs(dirs["XDG_CONFIG_DIR"]))

    return dirs


def _get_user_dirs(xdg_config_dir: pathlib.Path) -> dict[str, pathlib.Path]:
    """Returns a dict of XDG dirs read from
    ``$XDG_CONFIG_HOME/user-dirs.dirs``.

    This is used at import time for most users of :mod:`mopidy`. By rolling our
    own implementation instead of using :meth:`glib.get_user_special_dir` we
    make it possible for many extensions to run their test suites, which are
    importing parts of :mod:`mopidy`, in a virtualenv with global site-packages
    disabled, and thus no :mod:`glib` available.
    """

    dirs_file = xdg_config_dir / "user-dirs.dirs"

    if not dirs_file.exists():
        return {}

    data = dirs_file.read_bytes()
    data = b"[XDG_USER_DIRS]\n" + data
    data = data.replace(b"$HOME", bytes(pathlib.Path.home()))
    data = data.replace(b'"', b"")

    config = configparser.RawConfigParser()
    config.read_string(data.decode())

    result: dict[str, pathlib.Path] = {}
    for k, v in config.items("XDG_USER_DIRS"):
        if v is None:  # pyright: ignore[reportUnnecessaryComparison]
            continue
        if isinstance(k, bytes):
            k = k.decode()
        result[k.upper()] = pathlib.Path(v).resolve()

    return result
