import logging
import os
import subprocess

from pathlib import Path
from typing import Any, Iterable, Type


logger = logging.getLogger(__name__)


def get_env(
    name: str,
    cast: Type = str,
    required: bool = True,
    default: Any = None,
    split: str = "",
) -> Any:
    if cast is not str and split:
        raise TypeError(f"Split is not possible with {cast}")

    value = os.getenv(name)

    if not value:
        if required:
            logger.warning(f"Missing environment variable: {name}")

        return default

    bool_mapping = {"yes": True, "true": True, "false": False, "no": False}

    if cast is bool:
        _value = bool_mapping.get(value.lower())

        if not value:
            raise ValueError(f"Unknown boolean value: {_value}")

        return _value

    value = value if not cast else cast(value)
    return value if not split else value.split(split)


def get_current_version(debug: bool = True) -> str:
    version = get_env("VERSION", required=False)

    if version:
        return version

    if debug:
        try:
            output = subprocess.check_output(
                ["git", "show", "--no-patch", "--format=%H"], universal_newlines=True
            )
            return output.strip()
        except (subprocess.CalledProcessError, OSError):
            return ""

    try:
        output = subprocess.check_output(
            ["git", "describe", "--tags"], universal_newlines=True
        )
        return output.strip()
    except (subprocess.CalledProcessError, OSError):
        return ""


ROOT_MARKERS = ("pyproject.toml", "package.json", "README.md", "CHANGELOG.md")


def get_root_dir() -> Path:
    file = Path(__file__)
    return _traverse_dirs(file.parent, ROOT_MARKERS)


def _traverse_dirs(path: Path, root_markers: Iterable[str]) -> Path:
    if path.parent == path:
        raise OSError("Root directory detected")

    files = (file.name for file in path.iterdir())

    if not any((marker for marker in root_markers if marker in files)):
        return _traverse_dirs(path.parent, root_markers)

    return path
