#!/usr/bin/env bash
#
# Prism Pluggables Operations - Standalone CLI installer
#
# Usage:
#   curl -fsSL https://<your-host>/dist/prism-cli-install.sh | bash
#   curl -fsSL https://<your-host>/dist/prism-cli-install.sh | bash -s -- --user
#
# Environment:
#   PRISM_HOST        Base URL to download from (default: autodetected from script URL)
#   PRISM_PREFIX      Install prefix (default: $HOME/.local/prism-cli)
#   PRISM_CHANNEL     Release channel (default: stable)
#   PRISM_MODE        venv | user   (default: venv, falls back to user automatically)
#
set -euo pipefail

VERSION="1.0.0"
WHEEL="mdsi_transceiver_tools-${VERSION}-py3-none-any.whl"

PRISM_HOST="${PRISM_HOST:-}"
PRISM_PREFIX="${PRISM_PREFIX:-$HOME/.local/prism-cli}"
PRISM_CHANNEL="${PRISM_CHANNEL:-stable}"
PRISM_MODE="${PRISM_MODE:-venv}"

sanitize() {
    local v="$1"
    v="${v//$'\r'/}"
    v="${v//$'\n'/}"
    v="${v//[[:space:]]/}"
    printf '%s' "$v"
}

PRISM_HOST=$(sanitize "$PRISM_HOST")
PRISM_HOST="${PRISM_HOST%/}"

PRISM_PATH_CHOICE="${PRISM_PATH_CHOICE:-ask}"  # ask | yes | no

for arg in "$@"; do
    case "$arg" in
        --user) PRISM_MODE="user" ;;
        --venv) PRISM_MODE="venv" ;;
        --prefix=*) PRISM_PREFIX="${arg#--prefix=}" ;;
        --host=*) PRISM_HOST="${arg#--host=}" ;;
        --add-to-path) PRISM_PATH_CHOICE="yes" ;;
        --no-path) PRISM_PATH_CHOICE="no" ;;
    esac
done

C_BLUE=$'\033[1;34m'
C_DIM=$'\033[2m'
C_RED=$'\033[1;31m'
C_YEL=$'\033[1;33m'
C_OFF=$'\033[0m'

log()  { printf '%s[prism]%s %s\n' "$C_BLUE" "$C_OFF" "$*"; }
dim()  { printf '%s%s%s\n' "$C_DIM" "$*" "$C_OFF"; }
warn() { printf '%s[prism]%s %s\n' "$C_YEL" "$C_OFF" "$*" >&2; }
fail() { printf '%s[prism]%s %s\n' "$C_RED" "$C_OFF" "$*" >&2; exit 1; }

detect_distro() {
    if [ -r /etc/os-release ]; then
        # shellcheck disable=SC1091
        . /etc/os-release
        echo "${ID:-unknown}"
    else
        echo "unknown"
    fi
}

suggest_venv_fix() {
    local distro
    distro=$(detect_distro)
    case "$distro" in
        ubuntu|debian|linuxmint|pop)
            printf '  sudo apt-get update && sudo apt-get install -y python3-venv python3-pip\n'
            ;;
        fedora)
            printf '  sudo dnf install -y python3 python3-pip\n'
            ;;
        rhel|centos|rocky|almalinux)
            printf '  sudo dnf install -y python3 python3-pip  # or: sudo yum install -y python3 python3-pip\n'
            ;;
        arch|manjaro)
            printf '  sudo pacman -S --noconfirm python python-pip\n'
            ;;
        alpine)
            printf '  sudo apk add python3 py3-pip\n'
            ;;
        *)
            printf '  Install the python3 venv and pip packages from your distro repository.\n'
            ;;
    esac
    printf '  Or re-run this installer with --user to skip venv entirely:\n'
    printf '    curl -fsSL <url>/dist/prism-cli-install.sh | bash -s -- --user\n'
}

detect_host() {
    if [ -n "$PRISM_HOST" ]; then
        if [[ ! "$PRISM_HOST" =~ ^(https?|file):// ]]; then
            fail "PRISM_HOST must start with http://, https://, or file:// (got: ${PRISM_HOST})"
        fi
        return
    fi
    if [ -n "${BASH_SOURCE[0]:-}" ] && [ -f "${BASH_SOURCE[0]}" ]; then
        PRISM_HOST="file://$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
        PRISM_HOST="${PRISM_HOST%/dist}"
        return
    fi
    fail "PRISM_HOST is not set and cannot be auto-detected (running from a pipe).
  Re-run the installer with the host baked in, e.g.:
    curl -fsSL https://your-site/dist/prism-cli-install.sh | PRISM_HOST=https://your-site bash
  Or download the script first and run it locally:
    curl -fsSLo prism-install.sh https://your-site/dist/prism-cli-install.sh
    bash prism-install.sh"
}

require() {
    command -v "$1" >/dev/null 2>&1 || fail "Missing required tool: $1"
}

find_entry_point() {
    local bindir="$1"
    local candidate
    for candidate in mdsi-transceiver mdsi-transceiver-tools prism prism-cli; do
        if [ -x "${bindir}/${candidate}" ]; then
            printf '%s' "$candidate"
            return 0
        fi
    done
    return 1
}

download() {
    local src="$1" dest="$2"
    if [[ "$src" == file://* ]]; then
        cp "${src#file://}" "$dest" || fail "Unable to copy ${src}"
    elif command -v curl >/dev/null 2>&1; then
        if ! curl -fsSL "$src" -o "$dest"; then
            fail "Download failed: ${src}
  Check network / proxy settings, or that the URL is reachable from this host."
        fi
    elif command -v wget >/dev/null 2>&1; then
        if ! wget -q "$src" -O "$dest"; then
            fail "Download failed: ${src}"
        fi
    else
        fail "Neither curl nor wget is available. Install one (e.g. 'sudo apt-get install curl') and retry."
    fi
}

check_python() {
    if ! command -v python3 >/dev/null 2>&1; then
        fail "python3 is not installed.
  On Debian/Ubuntu: sudo apt-get install -y python3 python3-pip python3-venv
  On Fedora/RHEL:   sudo dnf install -y python3 python3-pip"
    fi

    local py_major py_minor
    py_major=$(python3 -c 'import sys; print(sys.version_info[0])')
    py_minor=$(python3 -c 'import sys; print(sys.version_info[1])')
    if [ "$py_major" -lt 3 ] || { [ "$py_major" -eq 3 ] && [ "$py_minor" -lt 7 ]; }; then
        fail "Python 3.7+ required (found ${py_major}.${py_minor})"
    fi
}

ensure_venv_capable() {
    local err
    if ! err=$(python3 -c 'import venv, ensurepip' 2>&1); then
        warn "This Python cannot create virtual environments."
        printf '%s\n' "$err" >&2
        echo
        warn "On this distro, try:"
        suggest_venv_fix
        return 1
    fi
    return 0
}

install_via_venv() {
    local tmpdir="$1"

    log "Creating isolated virtual environment"
    local venv_err
    if ! venv_err=$(python3 -m venv "${PRISM_PREFIX}/venv" 2>&1); then
        warn "Failed to create venv at ${PRISM_PREFIX}/venv"
        printf '%s\n' "$venv_err" >&2
        echo
        warn "Likely fix:"
        suggest_venv_fix
        return 1
    fi

    log "Installing into virtual environment"
    if ! "${PRISM_PREFIX}/venv/bin/pip" install --upgrade pip >"${tmpdir}/pip.log" 2>&1; then
        warn "pip upgrade failed. See ${tmpdir}/pip.log for details. Continuing with bundled pip."
    fi
    if ! "${PRISM_PREFIX}/venv/bin/pip" install "${tmpdir}/${WHEEL}" --ignore-requires-python >"${tmpdir}/install.log" 2>&1; then
        warn "pip install failed. Last 20 lines of the log:"
        tail -n 20 "${tmpdir}/install.log" >&2 || true
        return 1
    fi

    local entry
    entry=$(find_entry_point "${PRISM_PREFIX}/venv/bin") || {
        warn "Could not locate the installed CLI entry point in ${PRISM_PREFIX}/venv/bin"
        ls -1 "${PRISM_PREFIX}/venv/bin" >&2 || true
        return 1
    }

    mkdir -p "${PRISM_PREFIX}/bin"
    cat >"${PRISM_PREFIX}/bin/prism" <<SHIM
#!/usr/bin/env bash
HERE="\$(cd "\$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
exec "\${HERE}/venv/bin/${entry}" "\$@"
SHIM
    chmod +x "${PRISM_PREFIX}/bin/prism"
    ln -sf "${PRISM_PREFIX}/bin/prism" "${PRISM_PREFIX}/bin/prism-cli" 2>/dev/null || true
    return 0
}

install_via_user() {
    local tmpdir="$1"

    log "Installing with pip --user (no virtualenv)"

    if ! python3 -m pip --version >/dev/null 2>&1; then
        warn "pip is not available for this python3."
        printf '  On Debian/Ubuntu: sudo apt-get install -y python3-pip\n' >&2
        printf '  On Fedora/RHEL:   sudo dnf install -y python3-pip\n' >&2
        return 1
    fi

    local pip_args=(install --user --ignore-requires-python "${tmpdir}/${WHEEL}")
    if python3 -m pip help install 2>/dev/null | grep -q -- '--break-system-packages'; then
        pip_args+=(--break-system-packages)
    fi

    if ! python3 -m pip "${pip_args[@]}" >"${tmpdir}/install.log" 2>&1; then
        warn "pip --user install failed. Last 20 lines of the log:"
        tail -n 20 "${tmpdir}/install.log" >&2 || true
        return 1
    fi

    local user_base user_bin entry
    user_base=$(python3 -c 'import site; print(site.USER_BASE)')
    user_bin="${user_base}/bin"

    entry=$(find_entry_point "${user_bin}") || {
        warn "Package installed, but no CLI entry point was found in ${user_bin}"
        ls -1 "${user_bin}" 2>/dev/null >&2 || true
        return 1
    }

    mkdir -p "${PRISM_PREFIX}/bin"
    cat >"${PRISM_PREFIX}/bin/prism" <<SHIM
#!/usr/bin/env bash
exec "${user_bin}/${entry}" "\$@"
SHIM
    chmod +x "${PRISM_PREFIX}/bin/prism"
    ln -sf "${PRISM_PREFIX}/bin/prism" "${PRISM_PREFIX}/bin/prism-cli" 2>/dev/null || true
    return 0
}

detect_shell_profile() {
    local shell_name="${SHELL##*/}"
    case "$shell_name" in
        zsh)  printf '%s' "${ZDOTDIR:-$HOME}/.zshrc" ;;
        bash)
            if [ -f "$HOME/.bashrc" ]; then
                printf '%s' "$HOME/.bashrc"
            elif [ -f "$HOME/.bash_profile" ]; then
                printf '%s' "$HOME/.bash_profile"
            else
                printf '%s' "$HOME/.bashrc"
            fi
            ;;
        fish) printf '%s' "$HOME/.config/fish/config.fish" ;;
        *)    printf '%s' "$HOME/.profile" ;;
    esac
}

offer_path_update() {
    local bindir="$1"

    case ":${PATH}:" in
        *":${bindir}:"*)
            dim "  ${bindir} is already on your PATH."
            return 0
            ;;
    esac

    local profile
    profile=$(detect_shell_profile)

    local line
    if [[ "$profile" == *"config.fish" ]]; then
        line="set -gx PATH ${bindir} \$PATH"
    else
        line="export PATH=\"${bindir}:\$PATH\""
    fi

    if [ -f "$profile" ] && grep -Fq "$bindir" "$profile" 2>/dev/null; then
        dim "  A PATH entry for ${bindir} already exists in ${profile}."
        dim "  Open a new shell (or run: source ${profile}) to pick it up."
        return 0
    fi

    echo
    log "PATH setup"
    dim "  The 'prism' binary lives in ${bindir}, which is not on your PATH."
    dim "  To run 'prism' from anywhere, this line needs to be in your shell profile:"
    dim "    ${line}"
    dim "  I can append it to: ${profile}"
    echo

    local answer="$PRISM_PATH_CHOICE"
    if [ "$answer" = "ask" ]; then
        if [ ! -t 0 ] && [ ! -r /dev/tty ]; then
            warn "Non-interactive install; skipping PATH update."
            warn "Re-run with --add-to-path, or add this line manually to ${profile}:"
            printf '    %s\n' "$line" >&2
            return 0
        fi
        local prompt_src="/dev/stdin"
        [ ! -t 0 ] && [ -r /dev/tty ] && prompt_src="/dev/tty"
        local reply=""
        printf '%s[prism]%s Add it now? [y/N] ' "$C_BLUE" "$C_OFF"
        read -r reply <"$prompt_src" || reply=""
        case "$reply" in
            y|Y|yes|YES) answer="yes" ;;
            *)           answer="no"  ;;
        esac
    fi

    if [ "$answer" != "yes" ]; then
        log "Skipping PATH update. To add it yourself later:"
        printf '    echo %q >> %q\n' "$line" "$profile"
        return 0
    fi

    mkdir -p "$(dirname "$profile")"
    {
        printf '\n# Added by prism-cli installer on %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
        printf '%s\n' "$line"
    } >>"$profile"
    log "Appended PATH entry to ${profile}"
    dim "  Open a new shell, or run: source ${profile}"
}

main() {
    log "Prism CLI installer v${VERSION} (${PRISM_CHANNEL})"
    detect_host
    check_python

    log "Host    : ${PRISM_HOST}"
    log "Prefix  : ${PRISM_PREFIX}"
    log "Mode    : ${PRISM_MODE}"
    log "Distro  : $(detect_distro)"
    log "Python  : $(python3 --version 2>&1)"

    mkdir -p "${PRISM_PREFIX}"

    local tmpdir
    tmpdir=$(mktemp -d)
    trap 'rm -rf "$tmpdir"' EXIT

    log "Fetching ${WHEEL}"
    download "${PRISM_HOST%/}/dist/${WHEEL}" "${tmpdir}/${WHEEL}"

    local installed=0
    if [ "$PRISM_MODE" = "venv" ]; then
        if ensure_venv_capable && install_via_venv "$tmpdir"; then
            installed=1
        else
            warn "venv install failed. Falling back to --user install."
            if install_via_user "$tmpdir"; then
                installed=1
                PRISM_MODE="user"
            fi
        fi
    else
        if install_via_user "$tmpdir"; then
            installed=1
        fi
    fi

    if [ "$installed" -ne 1 ]; then
        fail "Install failed. See messages above. You can also download the wheel manually:
  ${PRISM_HOST%/}/dist/${WHEEL}
and run: python3 -m pip install --user ${WHEEL}"
    fi

    if ! "${PRISM_PREFIX}/bin/prism" --version >/dev/null 2>&1; then
        warn "Self-test of ${PRISM_PREFIX}/bin/prism failed. Diagnostic output:"
        "${PRISM_PREFIX}/bin/prism" --version >&2 || true
        warn "Shim contents:"
        sed -n '1,5p' "${PRISM_PREFIX}/bin/prism" >&2 || true
    fi

    log "Installed to ${PRISM_PREFIX} (${PRISM_MODE} mode)"
    dim "  Binary : ${PRISM_PREFIX}/bin/prism"
    if [ "$PRISM_MODE" = "venv" ]; then
        dim "  Venv   : ${PRISM_PREFIX}/venv"
    fi
    offer_path_update "${PRISM_PREFIX}/bin"

    echo
    log "Then try:"
    dim "    prism --version"
    dim "    prism list-profiles"
    dim "    prism show --port Ethernet0"
}

main "$@"
