# -*- coding: utf-8 -*-

"""Collection of the core utilities."""

from __future__ import annotations

__all__ = ['is_conda_available', 'get_conda_info']

import os
import sys
import typing
import json
from . import exceptions
from . import launch
from . import solvers

if typing.TYPE_CHECKING:
    import typing_extensions
    from . import types as conda_types


WIN: 'typing_extensions.Final[bool]' = (os.name == 'nt')


def get_conda_cmd_path() -> typing.Optional[str]:
    """Check if conda is found on path."""
    bin_folder: str = 'Scripts' if WIN else 'bin'
    conda_exe: str = 'conda-script.py' if WIN else 'conda'
    env_prefix: str = os.path.dirname(os.path.dirname(sys.prefix))
    cmds: typing.List[str] = [
        os.path.join(env_prefix, bin_folder, conda_exe),
        os.path.join(sys.prefix, bin_folder, conda_exe),
        'conda',
    ]

    cmd: str
    for cmd in cmds:
        stdout: str
        stderr: str
        error: bool
        stdout, stderr, error = launch.run_process(cmd_list=[cmd, '--version'])

        if (not error) and any(item.startswith('conda ') for item in (stdout, stderr)):
            return cmd

    return None


def is_conda_available() -> bool:
    """Check if conda is available in path."""
    return get_conda_cmd_path() is not None


def get_conda_info(allow_fixes: bool = False) -> typing.Optional['conda_types.CondaInfoOutput']:
    """Return conda info as a dictionary."""
    conda_cmd: typing.Optional[str] = get_conda_cmd_path()
    if conda_cmd is None:
        return None

    while True:
        out: str = launch.run_process(cmd_list=[conda_cmd, 'info', '--json']).stdout

        result: typing.Union['conda_types.CondaInfoOutput', 'conda_types.CondaErrorOutput']
        try:
            result = json.loads(out)
        except (TypeError, ValueError):
            return None

        if 'error' not in result:
            return typing.cast('conda_types.CondaInfoOutput', result)

        error: 'conda_types.CondaErrorOutput' = typing.cast('conda_types.CondaErrorOutput', result)
        if allow_fixes and (solvers.POOL.solve(error=error) is not None):
            continue
        raise exceptions.CondaError(error=error)
