#!/bin/sh

# prjct CLI - Runtime-agnostic entry point
#
# Detects available runtime (bun preferred, node fallback)
# and executes the appropriate entry point.
#
# CRITICAL: Also ensures p.md is installed (self-healing)
#
# @version 1.2.0

# Resolve symlinks to get the actual script location
resolve_symlink() {
  TARGET="$1"

  # Try readlink -f (Linux, newer macOS)
  if command -v readlink >/dev/null 2>&1; then
    RESOLVED="$(readlink -f "$TARGET" 2>/dev/null)"
    if [ -n "$RESOLVED" ]; then
      echo "$RESOLVED"
      return
    fi
  fi

  # Fallback: manual symlink resolution
  while [ -L "$TARGET" ]; do
    DIR="$(dirname "$TARGET")"
    TARGET="$(readlink "$TARGET")"
    # Handle relative symlinks
    case "$TARGET" in
      /*) ;;
      *) TARGET="$DIR/$TARGET" ;;
    esac
  done

  # Get absolute path
  DIR="$(cd "$(dirname "$TARGET")" && pwd)"
  echo "$DIR/$(basename "$TARGET")"
}

# Get the actual script location (resolving symlinks)
SCRIPT_PATH="$(resolve_symlink "$0")"
SCRIPT_DIR="$(dirname "$SCRIPT_PATH")"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"

# Ensure statusline and basic config (self-healing)
# Router (p.md) is deprecated — skills handle workflows natively
ensure_setup() {
  # Clean up legacy routers if they exist (deprecated — skills are native)
  for LEGACY_ROUTER in "$HOME/.claude/commands/p.md" "$HOME/.gemini/commands/p.toml"; do
    if [ -f "$LEGACY_ROUTER" ]; then
      rm -f "$LEGACY_ROUTER" 2>/dev/null
    fi
  done

  # Ensure statusline (best effort)
  STATUSLINE_SRC="$ROOT_DIR/assets/statusline/statusline.sh"
  STATUSLINE_DIR="$HOME/.prjct-cli/statusline"
  STATUSLINE_DEST="$STATUSLINE_DIR/statusline.sh"
  CLAUDE_STATUSLINE="$HOME/.claude/prjct-statusline.sh"

  if [ -f "$STATUSLINE_SRC" ]; then
    mkdir -p "$STATUSLINE_DIR" 2>/dev/null
    if [ ! -f "$STATUSLINE_DEST" ] || [ "$STATUSLINE_SRC" -nt "$STATUSLINE_DEST" ]; then
      cp "$STATUSLINE_SRC" "$STATUSLINE_DEST" 2>/dev/null
      chmod +x "$STATUSLINE_DEST" 2>/dev/null

      # Patch CLI_VERSION with actual version from package.json
      PKG_VERSION=$(grep '"version"' "$ROOT_DIR/package.json" 2>/dev/null | head -1 | sed 's/.*"version": *"\([^"]*\)".*/\1/')
      if [ -n "$PKG_VERSION" ]; then
        sed -i.bak "s/CLI_VERSION=\"[^\"]*\"/CLI_VERSION=\"$PKG_VERSION\"/" "$STATUSLINE_DEST" 2>/dev/null
        rm -f "$STATUSLINE_DEST.bak" 2>/dev/null
      fi

      # Copy lib, components, themes
      for subdir in lib components themes; do
        if [ -d "$ROOT_DIR/assets/statusline/$subdir" ]; then
          mkdir -p "$STATUSLINE_DIR/$subdir" 2>/dev/null
          cp "$ROOT_DIR/assets/statusline/$subdir"/* "$STATUSLINE_DIR/$subdir/" 2>/dev/null
        fi
      done

      # Symlink to ~/.claude
      rm -f "$CLAUDE_STATUSLINE" 2>/dev/null
      ln -s "$STATUSLINE_DEST" "$CLAUDE_STATUSLINE" 2>/dev/null || cp "$STATUSLINE_DEST" "$CLAUDE_STATUSLINE" 2>/dev/null
      chmod +x "$CLAUDE_STATUSLINE" 2>/dev/null
    fi
  fi

  # Ensure prjct skill is installed where Claude / Codex can see it.
  # postinstall is unreliable (--ignore-scripts, npm policies), so the
  # bin shim self-heals on every invocation. mtime-based: source newer
  # than dest → overwrite. Common case (skill up-to-date) = two stats.
  SKILL_SRC="$ROOT_DIR/templates/skills/prjct/SKILL.md"
  if [ -f "$SKILL_SRC" ]; then
    for SKILL_DEST in "$HOME/.claude/skills/prjct/SKILL.md" "$HOME/.codex/skills/prjct/SKILL.md"; do
      SKILL_DIR=$(dirname "$SKILL_DEST")
      if [ ! -f "$SKILL_DEST" ] || [ "$SKILL_SRC" -nt "$SKILL_DEST" ]; then
        mkdir -p "$SKILL_DIR" 2>/dev/null
        cp "$SKILL_SRC" "$SKILL_DEST" 2>/dev/null
      fi
    done
  fi
}

# Check if bun is available
check_bun() {
  command -v bun >/dev/null 2>&1
}

# Check if node is available
check_node() {
  command -v node >/dev/null 2>&1
}

# Run with bun (compiled dist preferred, TypeScript only for explicit dev)
run_with_bun() {
  # Always prefer compiled dist — works for npm install, npm link, bun link
  if [ -f "$ROOT_DIR/dist/bin/prjct.mjs" ]; then
    # Explicit dev mode: PRJCT_DEV=1 forces raw TypeScript (faster iteration)
    if [ "$PRJCT_DEV" = "1" ] && [ -f "$SCRIPT_DIR/prjct.ts" ]; then
      exec bun "$SCRIPT_DIR/prjct.ts" "$@"
    fi
    exec bun "$ROOT_DIR/dist/bin/prjct.mjs" "$@"
  fi
  # No dist: fall back to raw TypeScript (first run before build)
  if [ -f "$SCRIPT_DIR/prjct.ts" ]; then
    exec bun "$SCRIPT_DIR/prjct.ts" "$@"
  fi
  echo "Error: No entry point found. Run 'npm run build' first."
  exit 1
}

# Run with node (compiled JavaScript)
run_with_node() {
  DIST_BIN="$ROOT_DIR/dist/bin/prjct.mjs"

  if [ ! -f "$DIST_BIN" ]; then
    # No dist: try to build if this looks like a dev checkout
    if [ -f "$ROOT_DIR/scripts/build.js" ] && [ -d "$ROOT_DIR/core" ]; then
      echo "Building for Node.js (first run)..."
      node "$ROOT_DIR/scripts/build.js" || {
        echo "Error: Build failed. Run 'npm run build' manually."
        exit 1
      }
    else
      echo "Error: Compiled output not found. Run 'npm run build' first."
      exit 1
    fi
  fi

  exec node "$DIST_BIN" "$@"
}

# Main execution
main() {
  # ALWAYS ensure setup first (self-healing)
  ensure_setup

  # Prefer bun if available (faster, native TS support)
  if check_bun; then
    run_with_bun "$@"
  elif check_node; then
    # Bun not found but Node available — try auto-install Bun (one-time)
    ENSURE_BUN="$ROOT_DIR/scripts/ensure-bun.sh"
    if [ -f "$ENSURE_BUN" ]; then
      sh "$ENSURE_BUN"
      # Re-source PATH in case Bun was just installed
      export BUN_INSTALL="${BUN_INSTALL:-$HOME/.bun}"
      export PATH="$BUN_INSTALL/bin:$PATH"
      if check_bun; then
        run_with_bun "$@"
      fi
    fi
    run_with_node "$@"
  else
    echo "Error: Neither bun nor node is installed."
    echo ""
    echo "Please install one of:"
    echo "  - Bun (recommended): https://bun.sh"
    echo "  - Node.js 18+: https://nodejs.org"
    exit 1
  fi
}

main "$@"
