from configparser import ConfigParser
from pathlib import Path
import shutil
import os
import sys
import logging

logger = logging.getLogger(__name__)


CONFIG_FILE = Path(__file__).with_name('config.ini')


def _read_config():
    parser = ConfigParser()
    parser.read(CONFIG_FILE)
    return parser


def get_app_setting(name):
    config = _read_config()
    return config.get('app', name)


def get_app_float(name):
    config = _read_config()
    return config.getfloat('app', name)


def get_app_int(name):
    config = _read_config()
    return config.getint('app', name)


def get_optional_app_value(name):
    value = get_app_setting(name).strip()
    return value or None


def get_url(name):
    config = _read_config()
    return config.get('urls', name)


def get_path(name):
    config = _read_config()
    return config.get('paths', name)


def get_executable(name):
    """Return the configured executable name/path from the [executables] section.

    If not present, raises KeyError.
    """
    config = _read_config()
    return config.get('executables', name)


def validate_executables(required=None):
    """Validate that required executables are available.

    - If `required` is None, validate all entries in the [executables] section.
    - If an executable value is an absolute/relative path (contains os.sep), verify it exists and is executable.
    - Otherwise, resolve via `shutil.which` and return the resolved path.
    Returns a dict mapping name -> resolved_path.
    Exits the program on validation failure.
    """
    config = _read_config()
    if not config.has_section('executables'):
        return {}

    names = required or config.options('executables')
    resolved = {}
    for n in names:
        try:
            val = config.get('executables', n)
        except Exception:
            logger.error('Missing executable configuration: %s', n)
            sys.exit(1)

        if os.sep in val:
            if os.path.exists(val) and os.access(val, os.X_OK):
                resolved[n] = val
            else:
                logger.error('Configured executable for %s not found or not executable: %s', n, val)
                sys.exit(1)
        else:
            real = shutil.which(val)
            if real:
                resolved[n] = real
            else:
                logger.error('Executable %s (%s) not found in PATH', n, val)
                sys.exit(1)
    return resolved
