"""
Module for confiugration and misc things
"""
from __future__ import annotations

import os
import typing as ty
from pathlib import Path

import xdg.BaseDirectory as base

try:
    from kupfer import version_subst  # type:ignore
except ImportError:
    version_subst = None

PACKAGE_NAME = "kupfer"

__all__ = (
    "ResourceLookupError",
    "get_cache_file",
    "get_cache_home",
    "get_config_file",
    "get_config_files",
    "get_data_dirs",
    "get_data_file",
    "get_data_home",
    "get_kupfer_env",
    "has_capability",
    "save_config_file",
    "save_data_file",
)


class ResourceLookupError(Exception):
    pass


def has_capability(cap: str) -> bool:
    """Check is @cap capability is not disabled by environment variable"""
    return not bool(os.getenv(f"KUPFER_NO_{cap}"))


def get_kupfer_env(name: str, default: str = "") -> str:
    """Get valaue of KUPFER_<name> environment variable or default"""
    return os.getenv(f"KUPFER_{name}", default)


def get_cache_home() -> str | None:
    """Directory where cache files should be put.  Guaranteed to exist."""
    cache_home = base.xdg_cache_home or os.path.expanduser("~/.cache")
    cache_dir = Path(cache_home, PACKAGE_NAME)
    if not cache_dir.exists():
        try:
            cache_dir.mkdir(mode=0o700)
        except OSError as exc:
            print(exc)
            return None

    return str(cache_dir)


def get_cache_file(path: tuple[str, ...] = ()) -> str | None:
    """Get file by @path from cache directory.  Return None when no exists."""
    cache_home = base.xdg_cache_home or os.path.expanduser("~/.cache")
    cache_path = Path(cache_home, *path)
    if not cache_path.exists():
        return None

    return str(cache_path)


def get_data_file(filename: str, package: str = PACKAGE_NAME) -> str:
    """Return path to @filename if it exists anywhere in the data paths, else
    raise ResourceLookupError."""
    if version_subst:
        first_datadir = os.path.join(version_subst.DATADIR, package)
    else:
        first_datadir = "./data"

    file_path = Path(first_datadir, filename)
    if file_path.exists():
        return str(file_path)

    for data_path in base.load_data_paths(package):
        file_path = Path(data_path, filename)
        if file_path.exists():
            return str(file_path)

    if package == PACKAGE_NAME:
        raise ResourceLookupError(f"Resource {filename} not found")

    raise ResourceLookupError(
        f"Resource {filename} in package {package} not found"
    )


def save_data_file(filename: str) -> str | None:
    """Return filename in the XDG data home directory, where the directory is
    guaranteed to exist."""
    if direc := base.save_data_path(PACKAGE_NAME):
        return os.path.join(direc, filename)

    return None


def get_data_home() -> str:
    """Directory where data is to be saved. Guaranteed to exist."""
    return base.save_data_path(PACKAGE_NAME)


def get_data_dirs(
    name: str = "", package: str = PACKAGE_NAME
) -> ty.Iterable[str]:
    """Iterate over all data dirs of @name that exist."""
    return ty.cast(
        ty.Iterable[str], base.load_data_paths(os.path.join(package, name))
    )


def get_config_file(filename: str, package: str = PACKAGE_NAME) -> str | None:
    """Return path to @package/@filename if it exists anywhere in the config
    paths, else return None"""
    return ty.cast(
        ty.Union[str, None], base.load_first_config(package, filename)
    )


def get_config_files(filename: str) -> ty.Iterable[str]:
    """Iterator to @filename in all config paths, with most important (takes
    precendence) files first."""
    return base.load_config_paths(PACKAGE_NAME, filename) or ()


def save_config_file(filename: str) -> str | None:
    """Return filename in the XDG data home directory, where the directory
    is guaranteed to exist."""
    if direc := base.save_config_path(PACKAGE_NAME):
        return os.path.join(direc, filename)

    return None
