#!/usr/bin/env bash
# ── permagit installer v0.5.0 ────────────────────────────────────────
# Fully decentralized git backend using Arweave.
#
# Usage (bootstrap from Arweave — no dependencies besides node/npm/git):
#   curl -fsSL https://arweave.net/<INSTALLER_TX> | bash
#
# Or from a local clone:
#   git clone arweave://permagit && cd permagit && bash install.sh
#
# Requirements: node >= 18, npm, git, curl
# ─────────────────────────────────────────────────────────────────────
set -eo pipefail
# NOTE: We do NOT use "set -u" because BASH_SOURCE is unbound when
# this script is piped through bash (curl | bash).

VERSION="0.5.0"
PERMAGIT_HOME="${PERMAGIT_HOME:-$HOME/.permagit}"
INSTALL_DIR="$PERMAGIT_HOME/app"
BIN_DIR="${BIN_DIR:-/usr/local/bin}"

# ── Arweave settings ────────────────────────────────────────────────
GATEWAY="${PERMAGIT_GATEWAY:-https://arweave.net}"
GRAPHQL_URLS=(
  "$GATEWAY/graphql"
  "https://arweave-search.goldsky.com/graphql"
  "https://arweave.net/graphql"
)
# Fallback release TX — updated each time publish-release.js runs.
# If GraphQL hasn't indexed the latest release yet, we use this.
FALLBACK_RELEASE_TX="qVCsyydkgfdveOTyjoJ108BvbzdEyBEsq4Qk1DfUeKo"

# ── Colors ───────────────────────────────────────────────────────────
RED='\033[0;31m'
GREEN='\033[0;32m'
CYAN='\033[0;36m'
YELLOW='\033[0;33m'
BOLD='\033[1m'
DIM='\033[2m'
NC='\033[0m'

ok()   { echo -e "  ${GREEN}✓${NC} $1"; }
info() { echo -e "  ${CYAN}ℹ${NC} $1"; }
warn() { echo -e "  ${YELLOW}⚠${NC} $1"; }
fail() { echo -e "  ${RED}✗${NC} $1"; exit 1; }

echo ""
echo -e "${BOLD}╔══════════════════════════════════════════╗${NC}"
echo -e "${BOLD}║     ${CYAN}permagit${NC}${BOLD} installer ${DIM}v${VERSION}${NC}${BOLD}             ║${NC}"
echo -e "${BOLD}║  Decentralized git on Arweave            ║${NC}"
echo -e "${BOLD}╚══════════════════════════════════════════╝${NC}"
echo ""

# ── Check prerequisites ─────────────────────────────────────────────
check_cmd() {
  if ! command -v "$1" &>/dev/null; then
    fail "Required command not found: $1"
  fi
}
check_cmd node
check_cmd npm
check_cmd git
check_cmd curl

NODE_VER=$(node -e "process.stdout.write(String(process.versions.node.split('.')[0]))")
if [ "$NODE_VER" -lt 18 ]; then
  fail "Node.js >= 18 required (found v$(node -v))"
fi

ok "node $(node -v)"
ok "npm $(npm -v)"
ok "git $(git --version | cut -d' ' -f3)"
echo ""

# ── Determine install source ────────────────────────────────────────
# When run from a local clone/checkout, BASH_SOURCE is set.
# When piped via curl|bash, it is empty — we must bootstrap from Arweave.
SCRIPT_DIR=""
if [ -n "${BASH_SOURCE[0]:-}" ] && [ "${BASH_SOURCE[0]}" != "bash" ]; then
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd 2>/dev/null || echo "")"
fi

if [ -n "$SCRIPT_DIR" ] && [ -f "$SCRIPT_DIR/package.json" ] && [ -f "$SCRIPT_DIR/bin/git-remote-arweave.js" ]; then
  # Running from a clone/checkout — install from local source
  info "Installing from local source: $SCRIPT_DIR"
  SOURCE_DIR="$SCRIPT_DIR"
else
  # ── Bootstrap from Arweave ──────────────────────────────────────
  # Query the Arweave GraphQL endpoint for the latest release tarball.
  # Tags: App-Name=permagit, Type=release
  info "Bootstrapping permagit from Arweave..."

  GRAPHQL_QUERY='{"query":"{ transactions(tags: [{ name: \"App-Name\", values: [\"permagit\"] }, { name: \"Type\", values: [\"release\"] }], sort: HEIGHT_DESC, first: 1) { edges { node { id tags { name value } } } } }"}'

  RELEASE_TX=""
  for gql_url in "${GRAPHQL_URLS[@]}"; do
    RESPONSE=$(curl -sS --max-time 15 -X POST "$gql_url" \
      -H "Content-Type: application/json" \
      -d "$GRAPHQL_QUERY" 2>/dev/null || true)

    if [ -n "$RESPONSE" ]; then
      # Extract transaction ID — works with basic grep/sed (no jq dependency)
      # Use || true to prevent pipefail from killing the script when grep has no match
      RELEASE_TX=$(echo "$RESPONSE" | grep -o '"id":"[^"]*"' | head -1 | sed 's/"id":"//;s/"//' || true)
      if [ -n "$RELEASE_TX" ]; then
        break
      fi
    fi
  done

  if [ -z "$RELEASE_TX" ]; then
    if [ -n "$FALLBACK_RELEASE_TX" ]; then
      info "GraphQL index not ready, using known release fallback..."
      RELEASE_TX="$FALLBACK_RELEASE_TX"
    else
      fail "Could not find a permagit release on Arweave.
    The GraphQL query returned no results. This could mean:
      - The network is unreachable
      - No release has been published yet
    Try: curl -sSL https://arweave.net/<known-tarball-tx> | tar xz && cd permagit && bash install.sh"
    fi
  fi

  # Extract version from the GraphQL response tags (best-effort)
  RELEASE_VER=$(echo "${RESPONSE:-}" | grep -o '"name":"Version","value":"[^"]*"' | head -1 | sed 's/.*"value":"//;s/"//' 2>/dev/null || echo "latest")
  info "Found release: ${RELEASE_VER} (tx: ${RELEASE_TX})"

  TEMP_DIR=$(mktemp -d)
  trap "rm -rf $TEMP_DIR" EXIT

  info "Downloading release tarball..."
  HTTP_CODE=$(curl -sSL --max-time 120 -w "%{http_code}" -o "$TEMP_DIR/permagit.tar.gz" \
    "$GATEWAY/$RELEASE_TX" 2>/dev/null || echo "000")

  if [ "$HTTP_CODE" != "200" ]; then
    # Try alternate gateway
    HTTP_CODE=$(curl -sSL --max-time 120 -w "%{http_code}" -o "$TEMP_DIR/permagit.tar.gz" \
      "https://arweave.net/$RELEASE_TX" 2>/dev/null || echo "000")
  fi

  if [ "$HTTP_CODE" != "200" ]; then
    fail "Failed to download release tarball (HTTP $HTTP_CODE).
    TX: $RELEASE_TX
    Tried: $GATEWAY/$RELEASE_TX"
  fi

  ok "Downloaded release tarball"

  # Extract — the tarball has a permagit/ prefix
  cd "$TEMP_DIR"
  tar xzf permagit.tar.gz 2>/dev/null || fail "Failed to extract release tarball. The download may be corrupted."

  if [ -d "$TEMP_DIR/permagit" ]; then
    SOURCE_DIR="$TEMP_DIR/permagit"
  else
    # Tarball might extract without prefix; look for package.json
    if [ -f "$TEMP_DIR/package.json" ]; then
      SOURCE_DIR="$TEMP_DIR"
    else
      fail "Unexpected tarball structure — no permagit/ directory or package.json found."
    fi
  fi

  ok "Extracted release"
fi

# ── Install to ~/.permagit/app ───────────────────────────────────────
echo ""
info "Installing to $INSTALL_DIR"
mkdir -p "$INSTALL_DIR"

# Copy source files
for dir in src bin; do
  if [ -d "$SOURCE_DIR/$dir" ]; then
    mkdir -p "$INSTALL_DIR/$dir"
    cp -r "$SOURCE_DIR/$dir/"* "$INSTALL_DIR/$dir/"
  fi
done
cp "$SOURCE_DIR/package.json" "$INSTALL_DIR/"
[ -f "$SOURCE_DIR/package-lock.json" ] && cp "$SOURCE_DIR/package-lock.json" "$INSTALL_DIR/"
[ -f "$SOURCE_DIR/install.sh" ] && cp "$SOURCE_DIR/install.sh" "$INSTALL_DIR/"

ok "Source files copied"

# ── Install dependencies ────────────────────────────────────────────
info "Installing npm dependencies..."
cd "$INSTALL_DIR"
npm install --production --no-audit --no-fund 2>&1 | tail -1 | while read -r line; do
  echo "    $line"
done
ok "Dependencies installed"

# ── Create symlinks ─────────────────────────────────────────────────
echo ""
info "Creating symlinks in $BIN_DIR"

# Make binaries executable
chmod +x "$INSTALL_DIR/bin/git-remote-arweave.js"
chmod +x "$INSTALL_DIR/bin/permagit.js"

# Create symlinks (may need sudo)
create_link() {
  local src="$1"
  local dst="$2"
  if [ -w "$(dirname "$dst")" ]; then
    ln -sf "$src" "$dst"
    ok "Linked $dst"
  elif command -v sudo &>/dev/null; then
    sudo ln -sf "$src" "$dst"
    ok "Linked $dst (via sudo)"
  else
    warn "Cannot write to $(dirname "$dst"). Add $INSTALL_DIR/bin to your PATH instead."
    return 1
  fi
}

LINK_OK=true
create_link "$INSTALL_DIR/bin/git-remote-arweave.js" "$BIN_DIR/git-remote-arweave" || LINK_OK=false
create_link "$INSTALL_DIR/bin/permagit.js" "$BIN_DIR/permagit" || LINK_OK=false

if [ "$LINK_OK" = "false" ]; then
  echo ""
  warn "Add this to your shell profile:"
  echo "    export PATH=\"$INSTALL_DIR/bin:\$PATH\""
fi

# ── Generate wallet if needed ────────────────────────────────────────
echo ""
if [ -f "$PERMAGIT_HOME/wallet.json" ]; then
  ok "Wallet exists at $PERMAGIT_HOME/wallet.json"
else
  info "Generating Arweave wallet..."
  node -e "
    import Arweave from '$INSTALL_DIR/node_modules/arweave/node/index.mjs';
    import { writeFileSync, mkdirSync } from 'fs';
    const ar = Arweave.init({});
    const w = await ar.wallets.generate();
    mkdirSync('$PERMAGIT_HOME', { recursive: true });
    writeFileSync('$PERMAGIT_HOME/wallet.json', JSON.stringify(w, null, 2));
    const addr = await ar.wallets.jwkToAddress(w);
    console.log('  ✓ Wallet generated: ' + addr.slice(0, 8) + '…');
  " 2>/dev/null || {
    # Fallback: let permagit generate it on first use
    info "Wallet will be generated on first use"
  }
fi

# ── Done ─────────────────────────────────────────────────────────────
echo ""
echo -e "${BOLD}╔══════════════════════════════════════════╗${NC}"
echo -e "${BOLD}║  ${GREEN}permagit installed successfully!${NC}${BOLD}        ║${NC}"
echo -e "${BOLD}╚══════════════════════════════════════════╝${NC}"
echo ""
echo -e "  ${CYAN}Quick start:${NC}"
echo ""
echo -e "    ${DIM}# Create a new permanent repo${NC}"
echo -e "    permagit init my-project"
echo ""
echo -e "    ${DIM}# Clone an existing repo from Arweave${NC}"
echo -e "    git clone arweave://repo-name"
echo ""
echo -e "    ${DIM}# Push changes to Arweave${NC}"
echo -e "    git push arweave main"
echo ""
echo -e "    ${DIM}# Show wallet address${NC}"
echo -e "    permagit whoami"
echo ""
echo -e "  ${DIM}Docs: https://arweave.net/permagit${NC}"
echo ""
