#!/bin/bash

set -eo pipefail

PYTHON_VERSION_DEBIAN=3.11.6
VENV_NAME="openstack-env"
INSTALL_DIR="/opt/pf9/dependencies"
PYENV_ROOT="$INSTALL_DIR/.penv"
LOG_FILE="/var/log/pcdctl_setup.log"
URLS_FILE="$INSTALL_DIR/urls.txt"
S3_BUCKET="https://pcdctl.s3.us-west-2.amazonaws.com/pcdctl"
S3_PCDCTL_SHA256="https://pcdctl.s3.us-west-2.amazonaws.com/pcdctl.sha256sum"
PCDCTL_BIN="/usr/bin/pcdctl"
SKIP_OSCLI="${SKIP_OSCLI:-0}"
SPINNER_PID=""

TIMEOUT=10        # Default timeout in seconds
PROXY=""          # Default no proxy
PRIVATE_REPO_URL="https://artifacts.platform9.com/pcd" # Private repo base URL

# Parse command line arguments
while [[ $# -gt 0 ]]; do
  case $1 in
    --timeout=*)
      TIMEOUT="${1#*=}"
      shift
      ;;
    --proxy=*)
      PROXY="${1#*=}"
      shift
      ;;
    --private-repo-url=*)
      PRIVATE_REPO_URL="${1#*=}"
      shift
      ;;
    --timeout)
      TIMEOUT="$2"
      shift 2
      ;;
    --proxy)
      PROXY="$2"
      shift 2
      ;;
    --private-repo-url)
      PRIVATE_REPO_URL="$2"
      shift 2
      ;;
    *)
      # Unknown option
      shift
      ;;
  esac
done

mkdir -p "$INSTALL_DIR"
touch "$LOG_FILE"

log() {
    echo "$1" | tee -a "$LOG_FILE"
}

fatal() {
    echo "❌ $1" | tee -a "$LOG_FILE" >&2
    exit 1
}

if [[ -n "$PROXY" ]]; then
    log "Using proxy: $PROXY"
    export http_proxy="$PROXY"
    export https_proxy="$PROXY"
    export HTTP_PROXY="$PROXY"
    export HTTPS_PROXY="$PROXY"
    PROXY_ARGS="--proxy $PROXY"

    git config --global http.proxy "$PROXY"
    git config --global https.proxy "$PROXY"
else
    PROXY_ARGS=""
fi

spin() {
    local pid=$1
    local spin_chars='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'
    local i=0

    echo -n "⏳ Running setup "
    while kill -0 "$pid" 2>/dev/null; do
        i=$(( (i+1) % 10 ))
        printf "\r⏳ Running setup %s" "${spin_chars:$i:1}"
        sleep 0.1
    done
    printf "\r"
}

reboot_required() {
    # Debian family
    if [ -f /var/run/reboot-required ]; then
        return 0
    fi

    # RHEL family
    if command -v needs-restarting >/dev/null 2>&1; then
        if ! needs-restarting -r >/dev/null 2>&1; then
            return 0
        fi
    fi

    return 1
}

install_pcdctl() {
    log "⬇️  Installing pcdctl..."
    SHA_FILE="/tmp/pcdctl.sha256.$$"
    TMP_PCDCTL_BIN="/tmp/pcdctl"

    if [ ! -f "$URLS_FILE" ]; then
        cat <<EOF > "$URLS_FILE"
https://pcdctl.s3.us-west-2.amazonaws.com/pcdctl-setup
https://security.ubuntu.com/ubuntu
https://us.archive.ubuntu.com/ubuntu
https://ubuntu-cloud.archive.canonical.com/ubuntu
https://nova.clouds.archive.ubuntu.com/ubuntu
https://wiki.ubuntu.com/OpenStack/CloudArchive
https://api.snapcraft.io
https://auth.docker.io
https://cdn01.quay.io
https://check.percona.com
https://checkpoint-api.hashicorp.com
https://cr.fluentbit.io
https://dockermirror.platform9.io
https://gcr.io
https://pf9-airctl.s3-accelerate.amazonaws.com
https://prod-registry-k8s-io-us-east-1.s3.dualstack.us-east-1.amazonaws.com
https://production.cloudflare.docker.com
https://quay.io
https://registry-1.docker.io
https://registry.k8s.io
https://us-east4-docker.pkg.dev
https://usage.projectcalico.org
https://fedorapeople.org/
https://ghcr.io/
https://files.pythonhosted.org
https://pypi.org
EOF

        if [ ! -s "$URLS_FILE" ]; then
            log "❌ $URLS_FILE was created but is empty. Exiting."
            exit 1
        fi

        log "✅ $URLS_FILE created"
    else
        log "⚠️  $URLS_FILE already exists, skipping creation"
    fi

    if [ -f "$PCDCTL_BIN" ]; then
        PCDCTL_BAK_DIR="/tmp/pcdctl-backup-$(date +%s)"
        mkdir -p "$PCDCTL_BAK_DIR"
        log "⚠️  Existing pcdctl found, backing up to $PCDCTL_BAK_DIR..."
        sudo mv "$PCDCTL_BIN" "$PCDCTL_BAK_DIR"
    fi

    # Download checksum
    if ! curl -fsSL --connect-timeout "$TIMEOUT" $PROXY_ARGS "$S3_PCDCTL_SHA256" -o "$SHA_FILE"; then
        log "❌ Failed to download sha256 file from $S3_PCDCTL_SHA256"

        if [ -n "$PCDCTL_BAK_DIR" ] && [ -d "$PCDCTL_BAK_DIR" ]; then
            log "🔁 Restoring previous pcdctl binary..."
            sudo mv "$PCDCTL_BAK_DIR/pcdctl" "$PCDCTL_BIN"
        fi

        fatal "pcdctl installation failed; could not verify integrity"
    fi

    # Download binary
    log "⬇️  Downloading pcdctl binary..."

    if curl -fsSL --connect-timeout "$TIMEOUT" $PROXY_ARGS "$S3_BUCKET" -o "$TMP_PCDCTL_BIN"; then
        if (cd /tmp && sha256sum -c "$SHA_FILE" --status); then
            sudo chmod +x "$TMP_PCDCTL_BIN"
            mv "$TMP_PCDCTL_BIN" "$PCDCTL_BIN"
            log "✅ pcdctl installed successfully (checksum verified)"
            if [ -n "$PCDCTL_BAK_DIR" ] && [ -d "$PCDCTL_BAK_DIR" ]; then
                sudo rm -rf "$PCDCTL_BAK_DIR"
            fi
            rm -f "$SHA_FILE"

        else
            log "❌ SHA256 verification failed!"

            rm -f "$PCDCTL_BIN"

            if [ -n "$PCDCTL_BAK_DIR" ] && [ -d "$PCDCTL_BAK_DIR" ]; then
                log "🔁 Restoring previous pcdctl binary..."
                sudo mv "$PCDCTL_BAK_DIR/pcdctl" "$PCDCTL_BIN"
            fi

            fatal "pcdctl installation failed; checksum mismatch"
        fi

    else
        log "❌ Failed to download pcdctl from $S3_BUCKET"
        rm -f "$SHA_FILE"
        if [ -n "$PCDCTL_BAK_DIR" ] && [ -d "$PCDCTL_BAK_DIR" ]; then
            log "🔁 Restoring previous pcdctl binary..."
            sudo mv "$PCDCTL_BAK_DIR/pcdctl" "$PCDCTL_BIN"
        fi
        fatal "pcdctl installation failed; old binary restored"
    fi

    echo "✅ PCDCTL binary and url.txt installed" >> "$LOG_FILE"

    if [[ "$SKIP_OSCLI" == "1" || "$SKIP_OSCLI" == "true" ]]; then
        log "✅ Setup completed successfully!"
        exit 0
    fi

    # Check and fix symlinks for openstack and cinder
    for cmd in openstack cinder; do
        for bin_path in "$PYENV_ROOT/versions/$VENV_NAME/bin/$cmd"; do
            symlink_path="/usr/local/bin/$cmd"
            if [ -f "$bin_path" ]; then
                if [ ! -e "$symlink_path" ] || [ "$(readlink -f "$symlink_path" 2>/dev/null)" != "$(readlink -f "$bin_path")" ]; then
                    sudo rm -f "$symlink_path"
                    sudo ln -sf "$bin_path" "$symlink_path"
                fi
            fi
        done
    done

    if [ -f /usr/local/bin/openstack ]; then
        log "✅ PCD-VIRT Client already installed."
        exit 0
    fi
}


install_dependencies() {
    TMP_REQ=$(mktemp)

    (
        if [ -f /etc/debian_version ]; then
            sudo apt update
            sudo DEBIAN_FRONTEND=noninteractive NEEDRESTART_SUSPEND=1 \
                apt install -y make build-essential libssl-dev zlib1g-dev \
                    libbz2-dev libreadline-dev libsqlite3-dev xz-utils \
                    libffi-dev liblzma-dev git curl

            echo "✅ Verified checks"
            if [ -d "$HOME/.pyenv" ]; then
                echo "Moving existing pyenv to $PYENV_ROOT"
                mv "$HOME/.pyenv" "$PYENV_ROOT"
            fi

            if [ ! -d "$PYENV_ROOT" ]; then
                git clone https://github.com/pyenv/pyenv.git "$PYENV_ROOT"
                git clone https://github.com/pyenv/pyenv-virtualenv.git "$PYENV_ROOT/plugins/pyenv-virtualenv"
            fi

            export PYENV_ROOT="$PYENV_ROOT"
            export PATH="$PYENV_ROOT/bin:$PATH"
            eval "$(pyenv init --path)"
            eval "$(pyenv init -)"
            eval "$(pyenv virtualenv-init -)"

            if ! pyenv versions | grep -q "$PYTHON_VERSION_DEBIAN"; then
                pyenv install "$PYTHON_VERSION_DEBIAN"
            fi

            if [ ! -d "$PYENV_ROOT/versions/$VENV_NAME" ]; then
                pyenv virtualenv "$PYTHON_VERSION_DEBIAN" "$VENV_NAME"
            fi

            if [[ -n "$PROXY" ]]; then
                PIP_ARGS="$PIP_ARGS --proxy $PROXY"
            fi

            pyenv activate "$VENV_NAME"
            PIP="pip"
            OPENSTACK_BIN="$PYENV_ROOT/versions/$VENV_NAME/bin/openstack"
            CINDER_BIN="$PYENV_ROOT/versions/$VENV_NAME/bin/cinder"

        elif [ -f /etc/redhat-release ]; then
            VENV_DIR="/opt/pf9/$VENV_NAME"

            # Configure private YUM repo and pip if --private-repo-url was provided
            if [ -n "$PRIVATE_REPO_URL" ]; then
                sudo rm -f /etc/yum.repos.d/*.repo
                cat <<EOF | sudo tee /etc/yum.repos.d/platform9.repo
[platform9]
name=Platform9 YUM Repository
baseurl=${PRIVATE_REPO_URL}/yum
enabled=1
gpgcheck=1
gpgkey=${PRIVATE_REPO_URL}/RPM-GPG-KEY-platform9
EOF
                cat <<EOF | sudo tee /etc/pip.conf
[global]
index-url = ${PRIVATE_REPO_URL}/pypi/simple/
no-index = false
EOF
                sudo mkdir -p /root/.config/pip
                sudo ln -sf /etc/pip.conf /root/.config/pip/pip.conf
                echo "✅ Private repo configured"
            fi

            sudo mkdir -p /opt/pf9
            python3 -m venv "$VENV_DIR"

            if [[ -n "$PROXY" ]]; then
                PIP_ARGS="$PIP_ARGS --proxy $PROXY"
            fi

            PIP="$VENV_DIR/bin/pip"
            OPENSTACK_BIN="$VENV_DIR/bin/openstack"
            CINDER_BIN="$VENV_DIR/bin/cinder"

        else
            echo "Unsupported OS" && exit 1
        fi

        echo "✅ Environment setup completed"

        $PIP install $PIP_ARGS --upgrade pip || { echo "❌ Failed to upgrade pip"; exit 1; }

        cat <<EOF > "$TMP_REQ"
python-openstackclient==6.5.0
python-zaqarclient==1.10.0
python-novaclient==18.5.0
python-neutronclient==11.1.0
python-glanceclient==4.4.0
python-cinderclient==9.5.0
python-swiftclient==4.4.0
python-keystoneclient==5.1.0
python-heatclient==3.1.0
python-troveclient==8.0.0
python-ironicclient==3.1.0
python-octaviaclient==3.5.0
python-barbicanclient==5.5.0
python-designateclient==2.12.0
python-magnumclient==4.0.0
python-saharaclient==4.0.0
python-mistralclient==4.3.0
python-cloudkittyclient==4.5.0
python-vitrageclient==4.7.0
python-watcherclient==4.4.0
osc-placement==4.6.0
EOF

        $PIP install $PIP_ARGS -r "$TMP_REQ" || { echo "❌ Failed to install OpenStack clients"; exit 1; }

        if [ ! -f "$OPENSTACK_BIN" ]; then
            echo "❌ openstack binary not found"
            exit 1
        fi
        if [ ! -f "$CINDER_BIN" ]; then
            echo "❌ cinder binary not found"
            exit 1
        fi
    ) > "$LOG_FILE" 2>&1 &

    SCRIPT_PID=$!
    spin "$SCRIPT_PID"
    wait "$SCRIPT_PID"
    EXIT_CODE=$?

    printf "\r"

    if [ "$EXIT_CODE" -eq 0 ]; then
        # Create symlinks in the main shell where sudo has a TTY
        if [ -f /etc/redhat-release ]; then
            sudo ln -sf "/opt/pf9/$VENV_NAME/bin/openstack" /usr/local/bin/openstack
            sudo ln -sf "/opt/pf9/$VENV_NAME/bin/cinder" /usr/local/bin/cinder
        else
            sudo ln -sf "$PYENV_ROOT/versions/$VENV_NAME/bin/openstack" /usr/local/bin/openstack
            sudo ln -sf "$PYENV_ROOT/versions/$VENV_NAME/bin/cinder" /usr/local/bin/cinder
        fi
    fi

    return "$EXIT_CODE"
}

main() {

    # PRECHECK: Ensure no pending reboot before running pcdctl setup
    if reboot_required; then
        log "⚠️ WARNING: Host reboot is recommended before running setup."
    fi

    install_pcdctl

    log "⬇️  Installing dependencies"
    if install_dependencies; then
        log "✅ Dependencies installed successfully"

        if [ -f /usr/local/bin/openstack ]; then
            log "✅ Setup completed successfully!"
        else
            fatal "Openstack client not found after installation. Setup failed."
        fi
    else
        fatal "Setup failed. Check log at $LOG_FILE"
    fi
}


main
