# SPDX-License-Identifier: 0BSD
import platform
import re
import subprocess
import sys


def log_error_and_exit(logger, message):
    """Log an error message and exit with error"""
    logger.error(message)
    print()
    sys.exit(1)


def detect_aws_cli_version():
    """Returns (major: int, version_str: str) or (None, None) if not installed.

    NOTE: aws-cli v1 prints version to stderr; v2 prints to stdout.
    Concatenate both streams to capture the version regardless of stream.
    """
    try:
        result = subprocess.run(
            ["aws", "--version"],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            timeout=5,
            text=True,
        )
        output = (result.stdout or "") + (result.stderr or "")
        match = re.search(r"aws-cli/(\d+)\.", output)
        if match:
            return int(match.group(1)), output.strip()
    except (FileNotFoundError, subprocess.TimeoutExpired, OSError):
        pass
    return None, None


def get_v2_install_suggestions():
    """Returns platform-appropriate AWS CLI v2 installation options."""
    system = platform.system().lower()
    if system == "darwin":
        return [
            "  Option 1 (Homebrew):  brew install awscli",
            "  Option 2 (pkg):       https://awscli.amazonaws.com/AWSCLIV2.pkg",
        ]
    elif system == "linux":
        return [
            "  Option 1 (pkg mgr):   use your Linux package manager "
            "(apt, dnf, yum, pacman, zypper, etc.) to install 'awscli'",
            "  Option 2 (official):  "
            "https://docs.aws.amazon.com/cli/latest/userguide/"
            "getting-started-install.html",
        ]
    elif system == "windows":
        return [
            "  Option 1 (winget):    winget install Amazon.AWSCLI",
            "  Option 2 (choco):     choco install awscli",
        ]
    else:
        return [
            "  See: https://docs.aws.amazon.com/cli/latest/userguide/"
            "getting-started-install.html",
        ]


def get_otp_from_1password(item_name, logger):
    """Fetch a TOTP code from 1Password CLI.

    Returns the OTP string on success, or None on any failure (with a warning).
    """
    try:
        result = subprocess.run(
            ["op", "item", "get", item_name, "--otp"],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            timeout=30,
            text=True,
        )
        if result.returncode != 0:
            logger.warning(
                "1Password CLI failed for item '%s': %s",
                item_name,
                result.stderr.strip(),
            )
            return None
        otp = result.stdout.strip()
        if not otp:
            logger.warning("1Password returned empty OTP for item '%s'", item_name)
            return None
        return otp
    except FileNotFoundError:
        logger.warning("'op' CLI not found in PATH; cannot fetch MFA from 1Password")
        return None
    except subprocess.TimeoutExpired:
        logger.warning("'op' CLI timed out fetching OTP for item '%s'", item_name)
        return None


def prompter():
    return input


def getpass_starred(prompt=""):
    """Prompt for a secret, echoing * for each character typed.

    Falls back to no-echo (getpass behaviour) if the terminal cannot be
    put into raw mode (e.g. when stdin is piped/redirected).
    """
    sys.stdout.write(prompt)
    sys.stdout.flush()
    chars = []
    try:
        import tty
        import termios

        fd = sys.stdin.fileno()
        old = termios.tcgetattr(fd)
        try:
            tty.setraw(fd)
            while True:
                ch = sys.stdin.read(1)
                if ch in ("\r", "\n"):
                    break
                elif ch in ("\x7f", "\x08"):  # backspace / DEL
                    if chars:
                        chars.pop()
                        sys.stdout.write("\b \b")
                        sys.stdout.flush()
                elif ch == "\x03":  # Ctrl-C
                    raise KeyboardInterrupt
                else:
                    chars.append(ch)
                    sys.stdout.write("*")
                    sys.stdout.flush()
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old)
    except ImportError:
        import msvcrt

        while True:
            ch = msvcrt.getwch()
            if ch in ("\r", "\n"):
                break
            elif ch in ("\x08", "\x7f"):  # backspace
                if chars:
                    chars.pop()
                    sys.stdout.write("\b \b")
                    sys.stdout.flush()
            elif ch == "\x03":
                raise KeyboardInterrupt
            else:
                chars.append(ch)
                sys.stdout.write("*")
                sys.stdout.flush()
    except termios.error:
        import getpass

        sys.stdout.write("\n")
        return getpass.getpass("").strip()
    sys.stdout.write("\n")
    return "".join(chars)
