"""Shared CLI utilities: UI helpers, Docker probe, config dir, stdio kwargs."""

import subprocess
import sys
from pathlib import Path
from typing import Any, Dict, List, Optional

import questionary
from rich.console import Console

from armorer.config import resolve_armorer_config_dir

try:
    from InquirerPy import inquirer
    from InquirerPy.separator import Separator as InquirerSeparator

    _HAS_INQUIRERPY = True
except Exception:
    inquirer = None
    InquirerSeparator = None
    _HAS_INQUIRERPY = False

Separator = InquirerSeparator if _HAS_INQUIRERPY else questionary.Separator

console = Console()


def docker_cli_missing(detail: str) -> bool:
    """Return True if the error indicates the Docker CLI is not on PATH."""
    low_detail = str(detail or "").lower()
    windows_cli_missing = (
        "system cannot find the file specified" in low_detail
        and "docker" in low_detail
        and "//./pipe/docker_engine" not in low_detail
        and "docker_engine" not in low_detail
    )
    markers = (
        "docker: command not found",
        "no such file or directory: 'docker'",
        'no such file or directory: "docker"',
        "exec: \"docker\": executable file not found",
        "exec: \"docker\": file not found",
        "is not recognized as an internal or external command",
    )
    return windows_cli_missing or ("docker" in low_detail and any(marker in low_detail for marker in markers))


def docker_daemon_unavailable(detail: str) -> bool:
    low_detail = str(detail or "").lower()
    markers = (
        "/var/run/docker.sock",
        "permission denied while trying to connect",
        "cannot connect to the docker daemon",
        "is the docker daemon running?",
        "error during connect: this error may indicate that the docker daemon is not running",
        "//./pipe/docker_engine",
    )
    return any(marker in low_detail for marker in markers)


def probe_docker_daemon(detail_limit: int = 300) -> Optional[str]:
    """Return diagnostic details if Docker daemon is unreachable."""
    from armorer.messaging.bridge import _sanitize_bridge_user_text

    try:
        probe = subprocess.run(
            ["docker", "version", "--format", "{{.Server.Version}}"],
            capture_output=True,
            text=True,
        )
    except Exception as exc:
        return _sanitize_bridge_user_text(str(exc))[:detail_limit]
    if probe.returncode == 0:
        return None
    return (f"{probe.stdout or ''}\n{probe.stderr or ''}".strip() or "docker version check failed")[:detail_limit]


def armorer_config_dir() -> Path:
    return resolve_armorer_config_dir()


def ui_select(message: str, choices: List[Any], default: Optional[Any] = None):
    if _HAS_INQUIRERPY:
        kwargs: Dict[str, Any] = {"message": message, "choices": choices, "cycle": False}
        if default is not None:
            kwargs["default"] = default
        return inquirer.select(**kwargs).execute()
    return questionary.select(message, choices=choices, default=default).ask()


def ui_confirm(message: str, default: bool = True) -> bool:
    try:
        if _HAS_INQUIRERPY:
            return bool(inquirer.confirm(message=message, default=default).execute())
        return bool(questionary.confirm(message, default=default).ask())
    except TypeError:
        # Some test harnesses/mock stdin objects don't provide a real TTY
        # encoding, which can crash prompt_toolkit. Keep behavior
        # deterministic:
        # - For "Enable <channel>?" prompts, defaulting to enabled would
        #   trigger downstream secret prompts; instead, disable.
        # - For "is already configured. Keep it?" prompts and similar
        #   confirmations, respect the provided default.
        msg = str(message or "")
        msg_l = msg.strip().lower()
        if msg_l.startswith("enable ") and msg_l.endswith("?"):
            return False
        return default
    except Exception:
        return default


def ui_text(message: str, default: Optional[str] = None) -> Optional[str]:
    if _HAS_INQUIRERPY:
        kwargs = {"message": message}
        if default is not None:
            kwargs["default"] = default
        return inquirer.text(**kwargs).execute()
    return questionary.text(message, default=default).ask()


def ui_checkbox(message: str, choices: List[Any]):
    try:
        if _HAS_INQUIRERPY:
            return inquirer.checkbox(message=message, choices=choices).execute()
        return questionary.checkbox(message, choices=choices).ask()
    except TypeError:
        return []
    except Exception:
        return []


def ui_choice(title: str, value: Any, *, checked: bool = False) -> Any:
    if _HAS_INQUIRERPY:
        item = {"name": title, "value": value}
        if checked:
            item["enabled"] = True
        return item
    return questionary.Choice(title=title, value=value, checked=checked)


def ui_choice_value(choice: Any) -> Any:
    if isinstance(choice, dict):
        return choice.get("value")
    return getattr(choice, "value", choice)


def subprocess_stdio_kwargs() -> Dict[str, Any]:
    try:
        if sys.stdin.isatty() and sys.stdout.isatty():
            return {
                "stdin": sys.stdin,
                "stdout": sys.stdout,
                "stderr": sys.stderr,
            }
    except Exception:
        pass
    return {}
