#!/usr/bin/env bash
set -euo pipefail

# =============================================================================
# Indent Language — Universal Installer for Linux & macOS
# =============================================================================
#
# One-command install:
#   curl -fsSL https://raw.githubusercontent.com/xytrolabs/indent/main/scripts/install.sh | bash
#
# Local install (from build):
#   bash scripts/install.sh --local
#
# Specific version:
#   curl -fsSL ... | bash -s -- --version v2.1.0
# =============================================================================

DEFAULT_REPO="xytrolabs/indent"
REPO="${DEFAULT_REPO}"
LOCAL_MODE=0
BUILD_FROM_SOURCE=0
INDENT_VERSION="${INDENT_VERSION:-latest}"

bold()   { printf '\033[1m%s\033[0m' "$1"; }
green()  { printf '\033[32m%s\033[0m' "$1"; }
red()    { printf '\033[31m%s\033[0m' "$1"; }
yellow() { printf '\033[33m%s\033[0m' "$1"; }
warn()   { printf '\033[33m%s\033[0m' "$1" >&2; }

show_help() {
  cat <<'HELPEOF'
Indent Language Installer — Xytro Labs

Usage:
  curl -fsSL https://raw.githubusercontent.com/xytrolabs/indent/main/scripts/install.sh | bash
  bash install.sh [--local] [--version VER] [--repo OWNER/REPO]

Options:
  --local               Install from a local cargo build
  --build-from-source   Compile from source (requires Rust). Never done implicitly.
  --version VER         Install a specific release version (default: latest)
  --repo OWNER/REPO     GitHub repository for releases
  --help, -h            Show this help
HELPEOF
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --local) LOCAL_MODE=1 ;;
    --build-from-source) BUILD_FROM_SOURCE=1 ;;
    --version) INDENT_VERSION="$2"; shift ;;
    --repo) REPO="$2"; shift ;;
    --help|-h) show_help; exit 0 ;;
    *) warn "Unknown option: $1"; show_help; exit 2 ;;
  esac
  shift
done

OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
ARCH="$(uname -m)"

case "$OS" in
  linux)  OS_PART="unknown-linux-gnu" ;;
  darwin) OS_PART="apple-darwin" ;;
  *) red "Unsupported OS: $OS (Indent supports Linux and macOS)"; exit 1 ;;
esac

case "$ARCH" in
  x86_64|amd64) ARCH_PART="x86_64" ;;
  aarch64|arm64) ARCH_PART="aarch64" ;;
  *) red "Unsupported architecture: $ARCH"; exit 1 ;;
esac

TARGET="${ARCH_PART}-${OS_PART}"
CURL_OPTS=(--fail --silent --show-error --location --connect-timeout 10 --max-time 120 --retry 3 --retry-delay 2)

# Directory containing this installer (used for local share/ assets)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# ---- install paths ----
INDENT_HOME="${HOME}/.local/share/indent"
BIN_DIR="${INDENT_HOME}/bin"
STD_DIR="${INDENT_HOME}/std"
PKG_DIR="${INDENT_HOME}/packages"
LAUNCHER_DIR="${HOME}/.local/bin"
LAUNCHER="${LAUNCHER_DIR}/indent"
PROFILE_FILES=("${HOME}/.bashrc" "${HOME}/.zshrc" "${HOME}/.profile" "${HOME}/.bash_profile")

echo ""
bold "⚡ Indent Installer"
echo "  Platform: $(green "$TARGET")"
echo "  Home:     $INDENT_HOME"
echo ""

mkdir -p "$BIN_DIR" "$STD_DIR" "$PKG_DIR" "$LAUNCHER_DIR"

# ---- install binary ----
if [[ "$LOCAL_MODE" -eq 1 ]]; then
  echo "→ Installing from local build..."
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  LOCAL_BIN="${SCRIPT_DIR}/../indent-native/target/release/indent"
  if [[ ! -f "$LOCAL_BIN" ]]; then
    red "Local binary not found: $LOCAL_BIN"
    echo "  Build first: cd indent-native && cargo build --release"
    exit 1
  fi
  cp "$LOCAL_BIN" "${BIN_DIR}/indent"
  chmod +x "${BIN_DIR}/indent"
  green "✓ Installed from local build"
else
  echo "→ Fetching Indent ${INDENT_VERSION}..."
  if [[ "$INDENT_VERSION" == "latest" ]]; then
    API_URL="https://api.github.com/repos/${REPO}/releases/latest"
  else
    API_URL="https://api.github.com/repos/${REPO}/releases/tags/${INDENT_VERSION}"
  fi

  RELEASE_JSON="$(curl "${CURL_OPTS[@]}" "$API_URL" 2>/dev/null || true)"
  DOWNLOAD_URL="$(printf "%s" "$RELEASE_JSON" | grep -oE "https://[^\"]*indent-v[^\"]*-${TARGET}\\.tar\\.gz" | head -n1 || true)"

  if [[ -z "$DOWNLOAD_URL" ]]; then
    # Never force a compile. Some users have no toolchain and no way to install
    # one, so building from source is strictly opt-in via --build-from-source.
    if [[ "$BUILD_FROM_SOURCE" -ne 1 ]]; then
      red "No pre-built binary is available for ${TARGET} in ${REPO}."
      echo ""
      echo "  Nothing was compiled and nothing was changed."
      echo ""
      echo "  Indent installs a pre-built binary by default, so no compiler is needed."
      echo "  To get one, either:"
      echo ""
      echo "    - install a release that ships a ${TARGET} build:"
      echo "        https://github.com/${REPO}/releases"
      echo "    - or ask for a specific version that has one:"
      echo "        --version <tag>"
      echo ""
      echo "  If you do have Rust and want to compile it yourself:"
      echo "        --build-from-source"
      echo ""
      exit 1
    fi

    warn "No pre-built release found - building from source as requested..."
    echo "  (Rust is required for this: https://rustup.rs)"
    echo ""

    # Check for cargo
    if ! command -v cargo >/dev/null 2>&1; then
      if [[ -f "${HOME}/.cargo/env" ]]; then
        source "${HOME}/.cargo/env" 2>/dev/null || true
      fi
      if ! command -v cargo >/dev/null 2>&1; then
        red "Rust (cargo) not found. Install it first: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh"
        echo "  Then re-run this installer."
        exit 1
      fi
    fi

    # Sanity-check the toolchain. A broken or mismatched rustup install is by far
    # the most common reason this fallback fails on a freshly-installed machine
    # (symptom: "the 'rustc' binary ... is not applicable to the ... toolchain").
    if ! rustc -vV >/dev/null 2>&1; then
      red "Rust toolchain is broken or incomplete (rustc could not run)."
      echo "  This usually means a partial or mismatched rustup installation."
      echo ""
      echo "  Repair it, then re-run this installer:"
      echo ""
      echo "    rustup toolchain uninstall stable"
      echo "    rustup toolchain install stable --profile minimal"
      echo "    rustup default stable"
      echo ""
      echo "  Or install a fresh Rust toolchain:"
      echo ""
      echo "    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y"
      echo ""
      echo "  No Rust at all is needed for a pre-built binary; check for one at:"
      echo "    https://github.com/${REPO}/releases"
      exit 1
    fi

    # Clone and build from source
    BUILD_DIR="$(mktemp -d)"
    trap 'rm -rf "$BUILD_DIR"' EXIT
    echo "→ Cloning indent-native..."
    git clone --depth 1 "https://github.com/${REPO}.git" "$BUILD_DIR" 2>/dev/null || {
      red "Failed to clone ${REPO}"
      exit 1
    }
    cd "$BUILD_DIR/indent-native"
    echo "→ Building indent (release)..."
    cargo build --release 2>&1 | tail -3
    if [[ ! -f target/release/indent ]]; then
      red "Build failed. Check Rust toolchain: rustup default stable"
      exit 1
    fi
    cp target/release/indent "${BIN_DIR}/indent"
    chmod +x "${BIN_DIR}/indent"
    green "✓ Built and installed indent from source"

    # Build the native GUI helper (indent-gui) if a C toolchain + GTK/WebKit are available
    if command -v gcc >/dev/null 2>&1 && pkg-config --exists gtk+-3.0 webkit2gtk-4.1 2>/dev/null; then
      if [[ -f "$BUILD_DIR/indent-native/indent-gui.c" ]]; then
        echo "→ Building indent-gui (native HTML window helper)..."
        if gcc -o "${BIN_DIR}/indent-gui" "$BUILD_DIR/indent-native/indent-gui.c"              $(pkg-config --cflags --libs gtk+-3.0 webkit2gtk-4.1) 2>/dev/null; then
          chmod +x "${BIN_DIR}/indent-gui"
          green "✓ Built and installed indent-gui"
        else
          yellow "⚠ indent-gui build skipped (compile error); gui_show_html unavailable"
        fi
      fi

      # Build the InGame canvas helper (indent-ingame) too.
      if [[ -f "$BUILD_DIR/indent-native/indent-ingame.c" ]]; then
        echo "→ Building indent-ingame (native canvas game window)..."
        if gcc -o "${BIN_DIR}/indent-ingame" "$BUILD_DIR/indent-native/indent-ingame.c"              $(pkg-config --cflags --libs gtk+-3.0 webkit2gtk-4.1) 2>/dev/null; then
          chmod +x "${BIN_DIR}/indent-ingame"
          green "✓ Built and installed indent-ingame"
        else
          yellow "⚠ indent-ingame build skipped (compile error); InGame games unavailable"
        fi
      fi
    else
      yellow "⚠ GUI helpers skipped (need gcc + gtk3 + webkit2gtk dev headers for GUI)"
    fi

    # Copy companion tools from the cloned repo
    for tool in air; do
      if [[ -f "$BUILD_DIR/${tool}" ]]; then
        cp "$BUILD_DIR/${tool}" "${BIN_DIR}/${tool}"
        chmod +x "${BIN_DIR}/${tool}"
        cat > "${LAUNCHER_DIR}/${tool}" <<TOOLEOF
#!/usr/bin/env bash
exec "${BIN_DIR}/${tool}" "\$@"
TOOLEOF
        chmod +x "${LAUNCHER_DIR}/${tool}"
        green "✓ Installed $tool"
      fi
    done
  else

  TMP_DIR="$(mktemp -d)"
  trap 'rm -rf "$TMP_DIR"' EXIT
  curl "${CURL_OPTS[@]}" "$DOWNLOAD_URL" -o "${TMP_DIR}/indent.tar.gz"
  tar -xzf "${TMP_DIR}/indent.tar.gz" -C "$TMP_DIR"

  # Release archives are self-contained: they ship std/ and the companion
  # tools. Remember the unpack root so the stdlib step installs the complete
  # standard library from the archive instead of falling back to a partial
  # download of four files.
  RELEASE_ROOT="$(find "$TMP_DIR" -maxdepth 1 -type d -name 'indent-*' 2>/dev/null | head -n1 || true)"
  if [[ -n "$RELEASE_ROOT" && -d "${RELEASE_ROOT}/std" ]]; then
    STD_SOURCE_DIR="$RELEASE_ROOT"
  fi

  BIN_SRC="$(find "$TMP_DIR" -type f -name indent | head -n1)"
  if [[ -z "$BIN_SRC" ]]; then
    red "Archive does not contain 'indent' binary"
    exit 1
  fi
  cp "$BIN_SRC" "${BIN_DIR}/indent"
  chmod +x "${BIN_DIR}/indent"
  green "✓ Downloaded indent"

  # Install companion tools from the same release
  for tool in air; do
    TOOL_SRC="$(find "$TMP_DIR" -type f -name "$tool" | head -n1 || true)"
    if [[ -n "$TOOL_SRC" ]]; then
      cp "$TOOL_SRC" "${BIN_DIR}/${tool}"
      chmod +x "${BIN_DIR}/${tool}"
      cat > "${LAUNCHER_DIR}/${tool}" <<TOOLEOF
#!/usr/bin/env bash
exec "${BIN_DIR}/${tool}" "\$@"
TOOLEOF
      chmod +x "${LAUNCHER_DIR}/${tool}"
      green "✓ Installed $tool"
    fi
  done
fi
fi

# ---- install standard library ----
echo "→ Installing standard library..."

# Determine source for stdlib/packages:
# 1. STD_SOURCE_DIR - an unpacked prebuilt release archive (ships std/ + packages/)
# 2. BUILD_DIR     - the build-from-source fallback (cloned repo)
# 3. Local checkout (SCRIPT_DIR)
# 4. Download from GitHub
if [[ -n "${STD_SOURCE_DIR:-}" && -d "${STD_SOURCE_DIR}/std" ]]; then
  cp -r "${STD_SOURCE_DIR}/std"/* "$STD_DIR"/
  green "✓ Installed std/ from release archive"
  if [[ -d "${STD_SOURCE_DIR}/packages" ]]; then
    cp -r "${STD_SOURCE_DIR}/packages"/* "$PKG_DIR"/
    green "✓ Installed packages/ from release archive"
  fi
elif [[ -n "${BUILD_DIR:-}" && -d "${BUILD_DIR}/std" ]]; then
  cp -r "${BUILD_DIR}/std"/* "$STD_DIR"/
  green "✓ Installed std/ from cloned repo"
  if [[ -d "${BUILD_DIR}/packages" ]]; then
    cp -r "${BUILD_DIR}/packages"/* "$PKG_DIR"/
    green "✓ Installed packages/ from cloned repo"
  fi
else
  # Safe SCRIPT_DIR that doesn't break with set -u when piped
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-}")" 2>/dev/null && pwd || pwd)"
  LOCAL_STD="${SCRIPT_DIR}/../std"
  LOCAL_PKG="${SCRIPT_DIR}/../packages"

  if [[ -d "$LOCAL_STD" ]]; then
    cp -r "$LOCAL_STD"/* "$STD_DIR"/
    green "✓ Installed std/ from local checkout"
  else
    # Fallback for archives that do not bundle std/ — several published
    # releases shipped a bare `indent` binary. Fetch the source tree once so
    # the install still gets the COMPLETE standard library, AIR, and packages,
    # rather than a handful of hand-listed stdlib files.
    SRC_TMP="$(mktemp -d)"
    if curl "${CURL_OPTS[@]}" "https://github.com/${REPO}/archive/refs/heads/main.tar.gz" -o "${SRC_TMP}/src.tar.gz" 2>/dev/null; then
      if tar -xzf "${SRC_TMP}/src.tar.gz" -C "$SRC_TMP" 2>/dev/null; then
        SRC_ROOT="$(find "$SRC_TMP" -maxdepth 1 -type d -name 'indent-*' -print -quit || true)"
        if [[ -n "$SRC_ROOT" && -d "${SRC_ROOT}/std" ]]; then
          cp -r "${SRC_ROOT}/std"/* "$STD_DIR"/
          green "✓ Installed std/ from source tree"
        fi
        if [[ -n "$SRC_ROOT" && -d "${SRC_ROOT}/packages" ]]; then
          cp -r "${SRC_ROOT}/packages"/* "$PKG_DIR"/ 2>/dev/null || true
          green "✓ Installed packages/ from source tree"
        fi
        if [[ -n "$SRC_ROOT" && -f "${SRC_ROOT}/air" && ! -x "${BIN_DIR}/air" ]]; then
          cp "${SRC_ROOT}/air" "${BIN_DIR}/air"
          chmod +x "${BIN_DIR}/air"
          cat > "${LAUNCHER_DIR}/air" <<AIREOF
#!/usr/bin/env bash
exec "${BIN_DIR}/air" "\$@"
AIREOF
          chmod +x "${LAUNCHER_DIR}/air"
          green "✓ Installed air"
        fi
      fi
    fi
    rm -rf "$SRC_TMP"
  fi

  if [[ -d "$LOCAL_PKG" ]]; then
    cp -r "$LOCAL_PKG"/* "$PKG_DIR"/
    green "✓ Installed packages/ from local checkout"
  fi
fi

# ---- create launcher ----
cat > "$LAUNCHER" <<'LAUNCHEREOF'
#!/usr/bin/env bash
set -euo pipefail
INDENT_HOME="${HOME}/.local/share/indent"
# Include site-packages, packages, and std in INDENT_PATH (like Python's sys.path)
SITE_PKGS="${INDENT_HOME}/site-packages"
if [[ -z "${INDENT_PATH:-}" ]]; then
  export INDENT_PATH="${SITE_PKGS}:${INDENT_HOME}/packages:${INDENT_HOME}/std:${INDENT_HOME}"
else
  export INDENT_PATH="${SITE_PKGS}:${INDENT_HOME}/packages:${INDENT_HOME}/std:${INDENT_HOME}:${INDENT_PATH}"
fi
exec "${INDENT_HOME}/bin/indent" "$@"
LAUNCHEREOF
chmod +x "$LAUNCHER"
green "✓ Created launcher: $LAUNCHER"

# ---- auto-configure registry for air/aetherpkg ----
CONFIG_DIR="${HOME}/.config/indent"
mkdir -p "$CONFIG_DIR"
cat > "${CONFIG_DIR}/air.env" <<CFGEOF
AIR_REGISTRY_REPO=xytrolabs/air
AIR_REGISTRY_REF=main
AIR_REGISTRY_INDEX_PATH=packages/index.txt
CFGEOF

# ---- PATH setup ----
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
bold "✓ Indent installed successfully!"
echo ""
echo "  Binary:    ${BIN_DIR}/indent"
echo "  Launcher:  ${LAUNCHER}"
echo "  Stdlib:    ${STD_DIR}"
echo "  Packages:  ${PKG_DIR}"
echo ""

if [[ ":$PATH:" != *":$LAUNCHER_DIR:"* ]]; then
  warn "⚠  Add ${LAUNCHER_DIR} to your PATH:"
  echo ""
  echo "    export PATH=\"${LAUNCHER_DIR}:\$PATH\""
  echo ""
  read -r -p "  Add automatically to shell profile? [Y/n] " answer </dev/tty 2>/dev/null || true
  if [[ -z "$answer" || "$answer" =~ ^[Yy]$ ]]; then
    for profile in "${PROFILE_FILES[@]}"; do
      if [[ -f "$profile" ]] && ! grep -q "$LAUNCHER_DIR" "$profile" 2>/dev/null; then
        printf '\n# Indent language\nexport PATH="%s:$PATH"\n' "$LAUNCHER_DIR" >> "$profile"
        green "✓ Added to $profile"
      fi
    done
  fi
else
  green "✓ PATH already configured"
fi

echo ""
echo "  Try it:   $(bold 'indent --version')"
echo "  Format:   $(bold 'indent fmt myfile.ind')"
echo "  Help:     $(bold 'indent --help')"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""

# ---- VS Code extension auto-install helper ----
install_vsix_asset() {
  local url="$1"
  local slug="$2"
  local label="$3"

  if [[ -z "$url" ]]; then
    echo "VSIX for $label not found in latest release; skipping auto-install."
    return 0
  fi

  local vsix_path="$TMP_DIR/${slug}.vsix"
  if ! curl "${CURL_OPTS[@]}" "$url" -o "$vsix_path"; then
    echo "Warning: failed to download $label VSIX; skipping." >&2
    return 0
  fi

  if "${VSCODE_CLI:-false}" --install-extension "$vsix_path" --force >/dev/null 2>&1; then
    echo "Installed VS Code extension: $label"
  else
    echo "Warning: could not auto-install VS Code extension: $label" >&2
  fi
}

if [[ -n "${VSCODE_CLI:-}" ]]; then
  install_vsix_asset "${LANGUAGE_VSIX_URL:-}" "indent-language" "Indent Language"
  install_vsix_asset "${ICONS_VSIX_URL:-}" "indent-file-icons" "Indent File Icons"
else
  echo "VS Code CLI not found; skipping extension auto-install."
fi

# Configure VS Code user settings so .ind files are recognized in any folder.
if command -v jq >/dev/null 2>&1; then
  VSCODE_SETTINGS_PATHS=(
    "$HOME/.config/Code/User/settings.json"
    "$HOME/.config/VSCodium/User/settings.json"
  )

  for SETTINGS_FILE in "${VSCODE_SETTINGS_PATHS[@]}"; do
    SETTINGS_DIR="$(dirname "$SETTINGS_FILE")"
    mkdir -p "$SETTINGS_DIR"
    if [[ ! -f "$SETTINGS_FILE" ]]; then
      echo "{}" > "$SETTINGS_FILE"
    fi

    TMP_SETTINGS="$(mktemp)"
    jq '
      .["files.associations"] = ((.["files.associations"] // {}) + {"*.ind": "indent"}) |
      .["workbench.iconTheme"] = (.["workbench.iconTheme"] // "indent-seti-icons")
    ' "$SETTINGS_FILE" > "$TMP_SETTINGS" && mv "$TMP_SETTINGS" "$SETTINGS_FILE"
  done

  echo "Configured VS Code settings for .ind recognition and Indent icon theme defaults."
else
  echo "Optional: install 'jq' to auto-configure VS Code .ind settings during install."
fi

# ---- File manager integration (Indent file icon + MIME for .ind / .glo) ----
if [[ "$OS" == "linux" ]]; then
  FM_SHARE=""
  FM_SCRIPT=""

  # 1) Local repo assets (from-source --local, or a cloned build)
  if [[ -f "${SCRIPT_DIR}/install-file-manager.sh" && -d "${SCRIPT_DIR}/../share" ]]; then
    FM_SHARE="${SCRIPT_DIR}/../share"
    FM_SCRIPT="${SCRIPT_DIR}/install-file-manager.sh"
  elif [[ -n "${BUILD_DIR:-}" && -d "${BUILD_DIR}/share" ]]; then
    FM_SHARE="${BUILD_DIR}/share"
    FM_SCRIPT="${BUILD_DIR}/scripts/install-file-manager.sh"
  # 2) Prebuilt release: fetch the share assets + script from GitHub raw
  elif command -v curl >/dev/null 2>&1; then
    FM_DIR="$(mktemp -d)"
    FM_SCRIPT="${FM_DIR}/install-file-manager.sh"
    if curl "${CURL_OPTS[@]}" \
        "https://raw.githubusercontent.com/${REPO}/main/scripts/install-file-manager.sh" \
        -o "$FM_SCRIPT" 2>/dev/null; then
      mkdir -p "${FM_DIR}/share/mime/packages" \
               "${FM_DIR}/share/icons/hicolor/scalable/mimetypes" \
               "${FM_DIR}/share/applications"
      for f in \
          mime/packages/indent.xml \
          icons/hicolor/scalable/mimetypes/text-x-indent.svg \
          icons/hicolor/scalable/mimetypes/text-x-indent-env.svg \
          applications/indent.desktop; do
        curl "${CURL_OPTS[@]}" \
            "https://raw.githubusercontent.com/${REPO}/main/share/$f" \
            -o "${FM_DIR}/share/$f" 2>/dev/null || true
      done
      FM_SHARE="${FM_DIR}/share"
    fi
  fi

  if [[ -n "$FM_SHARE" && -f "$FM_SCRIPT" ]]; then
    bash "$FM_SCRIPT" --share-dir "$FM_SHARE"
  else
    echo "  (File-manager icon integration skipped — could not locate share assets)" >&2
  fi
fi
