#!/usr/bin/env bash
#
# CIEL Installer Script
# Validates system requirements, installs runtime dependencies,
# and deploys the CIEL Controller standalone binary on Linux.
#
# Usage:
#   curl -fsSL https://dl.cielstack.com/install.sh | bash
#   curl -fsSL https://dl.cielstack.com/install.sh | sudo bash
#   curl -fsSL https://dl.cielstack.com/install.sh | bash -s -- --version v1.0.0
#   CIEL_INSTALL_DIR="$HOME/.local/bin" curl -fsSL https://dl.cielstack.com/install.sh | bash
#

set -euo pipefail

BASE_URL="${CIEL_BASE_URL:-https://dl.cielstack.com}"
DEFAULT_INSTALL_DIR="/usr/local/bin"
TARGET_BIN_NAME="ciel"
REQUESTED_VERSION="${CIEL_VERSION:-}"
CUSTOM_INSTALL_DIR="${CIEL_INSTALL_DIR:-}"
SKIP_CHECKSUM="${CIEL_SKIP_CHECKSUM:-0}"
SKIP_DEPS="${CIEL_SKIP_DEPS:-0}"

# Parse command line options
while [[ $# -gt 0 ]]; do
  case "$1" in
    -v|--version)
      REQUESTED_VERSION="$2"
      shift 2
      ;;
    -d|--dir)
      CUSTOM_INSTALL_DIR="$2"
      shift 2
      ;;
    --skip-deps|--no-deps)
      SKIP_DEPS=1
      shift
      ;;
    --skip-checksum)
      SKIP_CHECKSUM=1
      shift
      ;;
    -h|--help)
      echo "Usage: install.sh [OPTIONS]"
      echo ""
      echo "Options:"
      echo "  -v, --version <version>  Specify CIEL release version (e.g. v1.0.0)"
      echo "  -d, --dir <path>         Target installation directory (default: /usr/local/bin)"
      echo "      --skip-deps          Skip package validation and automatic installation"
      echo "      --skip-checksum      Skip SHA-256 integrity verification"
      echo "  -h, --help               Display this help message"
      exit 0
      ;;
    *)
      echo "[ERROR] Unknown option: $1" >&2
      exit 1
      ;;
  esac
done

echo "=================================================="
echo "           CIEL Controller Installer              "
echo "=================================================="

# 1. Validate Operating System
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
if [ "$OS" != "linux" ]; then
  echo "[ERROR] CIEL standalone binary currently only supports Linux (detected: $OS)." >&2
  exit 1
fi

# 2. Validate Architecture
ARCH="$(uname -m)"
case "$ARCH" in
  x86_64|amd64)
    ARCH_SUFFIX="linux-amd64"
    ;;
  *)
    echo "[ERROR] Architecture '$ARCH' is currently unsupported (supported: x86_64 / amd64)." >&2
    exit 1
    ;;
esac

# 3. Detect Package Manager
detect_package_manager() {
  if command -v apt-get >/dev/null 2>&1; then
    echo "apt"
  elif command -v dnf >/dev/null 2>&1; then
    echo "dnf"
  elif command -v yum >/dev/null 2>&1; then
    echo "yum"
  elif command -v pacman >/dev/null 2>&1; then
    echo "pacman"
  elif command -v zypper >/dev/null 2>&1; then
    echo "zypper"
  elif command -v apk >/dev/null 2>&1; then
    echo "apk"
  else
    echo "unknown"
  fi
}

PKG_MGR="$(detect_package_manager)"

# 4. Validate and Automatically Install Dependencies
if [ "$SKIP_DEPS" -eq 0 ]; then
  echo "[INFO] Checking required system dependencies..."
  PACKAGES_TO_INSTALL=()

  # Check curl or wget
  if ! command -v curl >/dev/null 2>&1 && ! command -v wget >/dev/null 2>&1; then
    case "$PKG_MGR" in
      apt|dnf|yum|pacman|zypper|apk) PACKAGES_TO_INSTALL+=("curl") ;;
    esac
  fi

  # Check OpenSSH client
  if ! command -v ssh >/dev/null 2>&1; then
    case "$PKG_MGR" in
      apt|apk) PACKAGES_TO_INSTALL+=("openssh-client") ;;
      dnf|yum) PACKAGES_TO_INSTALL+=("openssh-clients") ;;
      pacman|zypper) PACKAGES_TO_INSTALL+=("openssh") ;;
    esac
  fi

  # Check sshpass (required for password-based host authentication)
  if ! command -v sshpass >/dev/null 2>&1; then
    PACKAGES_TO_INSTALL+=("sshpass")
  fi

  # Check rsync (required for file synchronization)
  if ! command -v rsync >/dev/null 2>&1; then
    PACKAGES_TO_INSTALL+=("rsync")
  fi

  # Check git (required for Git-based projects and Ansible Galaxy roles)
  if ! command -v git >/dev/null 2>&1; then
    PACKAGES_TO_INSTALL+=("git")
  fi

  # Check execution engine (Podman or Ansible)
  if ! command -v podman >/dev/null 2>&1 && ! command -v docker >/dev/null 2>&1 && ! command -v ansible >/dev/null 2>&1; then
    echo "[INFO] No execution engine detected (Podman, Docker, or Ansible)."
    case "$PKG_MGR" in
      apt|dnf|yum|pacman|zypper|apk)
        PACKAGES_TO_INSTALL+=("podman")
        ;;
    esac
  fi

  if [ ${#PACKAGES_TO_INSTALL[@]} -gt 0 ]; then
    echo "[INFO] Missing system packages detected: ${PACKAGES_TO_INSTALL[*]}"

    SUDO_PREFIX=""
    if [ "$(id -u)" -ne 0 ]; then
      if command -v sudo >/dev/null 2>&1; then
        SUDO_PREFIX="sudo"
      else
        echo "[ERROR] Root or sudo privilege is required to install system packages: ${PACKAGES_TO_INSTALL[*]}" >&2
        echo "        Please install them manually using your package manager, or pass --skip-deps." >&2
        exit 1
      fi
    fi

    echo "[INFO] Installing packages via ${PKG_MGR}..."
    case "$PKG_MGR" in
      apt)
        $SUDO_PREFIX apt-get update -qq
        $SUDO_PREFIX DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends "${PACKAGES_TO_INSTALL[@]}"
        ;;
      dnf)
        $SUDO_PREFIX dnf install -y "${PACKAGES_TO_INSTALL[@]}"
        ;;
      yum)
        $SUDO_PREFIX yum install -y "${PACKAGES_TO_INSTALL[@]}"
        ;;
      pacman)
        $SUDO_PREFIX pacman -Sy --noconfirm --needed "${PACKAGES_TO_INSTALL[@]}"
        ;;
      zypper)
        $SUDO_PREFIX zypper --non-interactive in "${PACKAGES_TO_INSTALL[@]}"
        ;;
      apk)
        $SUDO_PREFIX apk add --no-cache "${PACKAGES_TO_INSTALL[@]}"
        ;;
      *)
        echo "[WARN] Unable to determine package manager. Please install manually: ${PACKAGES_TO_INSTALL[*]}"
        ;;
    esac
    echo "[OK] Dependencies successfully installed."
  else
    echo "[OK] All required system dependencies are satisfied."
  fi
else
  echo "[INFO] Dependency verification skipped via --skip-deps."
fi

# 5. Detect Download Utility
DOWNLOADER=""
if command -v curl >/dev/null 2>&1; then
  DOWNLOADER="curl"
elif command -v wget >/dev/null 2>&1; then
  DOWNLOADER="wget"
else
  echo "[ERROR] 'curl' or 'wget' is required to download CIEL." >&2
  exit 1
fi

download_file() {
  local url="$1"
  local dest="$2"
  if [ "$DOWNLOADER" = "curl" ]; then
    curl -fsSL "$url" -o "$dest"
  else
    wget -qO "$dest" "$url"
  fi
}

download_stdout() {
  local url="$1"
  if [ "$DOWNLOADER" = "curl" ]; then
    curl -fsSL "$url"
  else
    wget -qO- "$url"
  fi
}

# 6. Resolve Target Release Version
RESOLVED_VERSION="$REQUESTED_VERSION"
EXPECTED_SHA256=""

if [ -z "$RESOLVED_VERSION" ]; then
  echo "[INFO] Resolving latest release from ${BASE_URL}/latest.json..."
  LATEST_META=""
  if LATEST_META="$(download_stdout "${BASE_URL}/latest.json" 2>/dev/null)"; then
    if command -v python3 >/dev/null 2>&1; then
      RESOLVED_VERSION="$(python3 -c "import json, sys; d=json.loads(sys.stdin.read()); print(d.get('tag') or ('v' + d.get('version','')))" <<< "$LATEST_META")"
      EXPECTED_SHA256="$(python3 -c "import json, sys; d=json.loads(sys.stdin.read()); print(d.get('binaries', {}).get('${ARCH_SUFFIX}', {}).get('sha256', '') or d.get('sha256', ''))" <<< "$LATEST_META")"
    elif command -v jq >/dev/null 2>&1; then
      RESOLVED_VERSION="$(jq -r '.tag // ("v" + .version)' <<< "$LATEST_META")"
      EXPECTED_SHA256="$(jq -r ".binaries[\"${ARCH_SUFFIX}\"].sha256 // .sha256 // \"\"" <<< "$LATEST_META")"
    else
      RESOLVED_VERSION="$(grep -o '"tag"[[:space:]]*:[[:space:]]*"[^"]*"' <<< "$LATEST_META" | head -n1 | cut -d'"' -f4 || true)"
      if [ -z "$RESOLVED_VERSION" ]; then
        RAW_VER="$(grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' <<< "$LATEST_META" | head -n1 | cut -d'"' -f4 || true)"
        [ -n "$RAW_VER" ] && RESOLVED_VERSION="v${RAW_VER}"
      fi
    fi
  fi

  if [ -z "$RESOLVED_VERSION" ] || [ "$RESOLVED_VERSION" = "null" ]; then
    RESOLVED_VERSION="v1.0.0"
    echo "[WARN] Could not retrieve latest release metadata. Using fallback version: ${RESOLVED_VERSION}"
  fi
fi

# Normalize version prefix (ensure leading 'v')
if [[ ! "$RESOLVED_VERSION" =~ ^v ]]; then
  RESOLVED_VERSION="v${RESOLVED_VERSION}"
fi

echo "[INFO] Target version: ${RESOLVED_VERSION} (${ARCH_SUFFIX})"

# 7. Prepare Temporary Directory
TMP_DIR="$(mktemp -d -t ciel-install-XXXXXX)"
cleanup() {
  rm -rf "$TMP_DIR"
}
trap cleanup EXIT

BINARY_FILENAME="ciel-${ARCH_SUFFIX}"
BINARY_URL="${BASE_URL}/${RESOLVED_VERSION}/${BINARY_FILENAME}"
CHECKSUM_URL="${BASE_URL}/${RESOLVED_VERSION}/${BINARY_FILENAME}.sha256"
LOCAL_TMP_BINARY="${TMP_DIR}/${BINARY_FILENAME}"
LOCAL_TMP_SHA="${TMP_DIR}/${BINARY_FILENAME}.sha256"

# 8. Download Binary
echo "[INFO] Downloading binary: ${BINARY_URL}..."
if ! download_file "$BINARY_URL" "$LOCAL_TMP_BINARY"; then
  echo "[ERROR] Failed to download binary from ${BINARY_URL}." >&2
  exit 1
fi

# 9. Verify SHA-256 Checksum
if [ "$SKIP_CHECKSUM" -eq 0 ]; then
  if [ -z "$EXPECTED_SHA256" ]; then
    if download_file "$CHECKSUM_URL" "$LOCAL_TMP_SHA" 2>/dev/null; then
      EXPECTED_SHA256="$(awk '{print $1}' "$LOCAL_TMP_SHA" | head -n1)"
    fi
  fi

  if [ -n "$EXPECTED_SHA256" ]; then
    echo "[INFO] Verifying SHA-256 checksum..."
    CALCULATED_SHA256=""
    if command -v sha256sum >/dev/null 2>&1; then
      CALCULATED_SHA256="$(sha256sum "$LOCAL_TMP_BINARY" | awk '{print $1}')"
    elif command -v shasum >/dev/null 2>&1; then
      CALCULATED_SHA256="$(shasum -a 256 "$LOCAL_TMP_BINARY" | awk '{print $1}')"
    fi

    if [ -n "$CALCULATED_SHA256" ]; then
      if [ "$CALCULATED_SHA256" != "$EXPECTED_SHA256" ]; then
        echo "[ERROR] SHA-256 checksum mismatch!" >&2
        echo "  Expected: $EXPECTED_SHA256" >&2
        echo "  Actual:   $CALCULATED_SHA256" >&2
        exit 1
      fi
      echo "[OK] Checksum verified: ${CALCULATED_SHA256}"
    else
      echo "[WARN] No sha256 utility found. Skipping checksum verification."
    fi
  else
    echo "[INFO] Checksum file not found on release server. Skipping verification."
  fi
fi

# 10. Determine Target Installation Directory
TARGET_DIR="${CUSTOM_INSTALL_DIR:-$DEFAULT_INSTALL_DIR}"
USE_SUDO=0

if [ ! -d "$TARGET_DIR" ]; then
  if [ -w "$(dirname "$TARGET_DIR")" ] 2>/dev/null; then
    mkdir -p "$TARGET_DIR"
  else
    USE_SUDO=1
  fi
elif [ ! -w "$TARGET_DIR" ]; then
  USE_SUDO=1
fi

TARGET_FILE="${TARGET_DIR}/${TARGET_BIN_NAME}"

# 11. Install Binary
echo "[INFO] Installing binary to ${TARGET_FILE}..."
if [ "$USE_SUDO" -eq 1 ]; then
  if command -v sudo >/dev/null 2>&1; then
    sudo mkdir -p "$TARGET_DIR"
    sudo cp -f "$LOCAL_TMP_BINARY" "$TARGET_FILE"
    sudo chmod 755 "$TARGET_FILE"
  else
    echo "[WARN] Sudo/root permissions unavailable for ${TARGET_DIR}."
    TARGET_DIR="$HOME/.local/bin"
    TARGET_FILE="${TARGET_DIR}/${TARGET_BIN_NAME}"
    echo "[INFO] Falling back to user directory: ${TARGET_DIR}"
    mkdir -p "$TARGET_DIR"
    cp -f "$LOCAL_TMP_BINARY" "$TARGET_FILE"
    chmod 755 "$TARGET_FILE"
  fi
else
  cp -f "$LOCAL_TMP_BINARY" "$TARGET_FILE"
  chmod 755 "$TARGET_FILE"
fi

# 12. Sanity Check Execution
echo "[INFO] Verifying binary execution..."
if "$TARGET_FILE" version >/dev/null 2>&1; then
  INSTALLED_VER="$("$TARGET_FILE" version 2>&1 | head -n1)"
  echo "[OK] Verification succeeded: ${INSTALLED_VER}"
else
  echo "[WARN] Binary installed, but 'ciel version' failed. Please check host GLIBC compatibility."
fi

# 13. Check PATH
case ":$PATH:" in
  *":$TARGET_DIR:"*)
    ;;
  *)
    echo ""
    echo "[NOTE] '${TARGET_DIR}' is not in your system PATH."
    echo "       Add the following line to your ~/.bashrc or ~/.zshrc:"
    echo "       export PATH=\"${TARGET_DIR}:\$PATH\""
    ;;
esac

echo ""
echo "=================================================="
echo "[OK] CIEL Controller successfully installed!"
echo "Binary path: ${TARGET_FILE}"
echo ""
echo "Quick start:"
echo "  ciel --help        Show available commands"
echo "  ciel version       Show binary version"
echo "  ciel doctor        Inspect system dependencies"
echo "  ciel start         Launch CIEL Controller"
echo "=================================================="
