#!/usr/bin/env bash
# dopeTask Unified Installer
# Supports: GitHub Packages, Git tag/commit, Local editable install
# Verifies installation with dopetask doctor

set -euo pipefail

# ============================================================================
# Configuration & Defaults
# ============================================================================

MODE="${1:-auto}"
VERIFY_ONLY=false
LOCKFILE="./DOPETASK_VERSION.lock"
WRITE_LOCK=false
PRINT_CONFIG=false

# Parse arguments
while [[ $# -gt 0 ]]; do
  case "$1" in
    --mode)
      MODE="$2"
      shift 2
      ;;
    --verify-only)
      VERIFY_ONLY=true
      shift
      ;;
    --lockfile)
      LOCKFILE="$2"
      shift 2
      ;;
    --write-lock)
      WRITE_LOCK=true
      shift
      ;;
    --print-config)
      PRINT_CONFIG=true
      shift
      ;;
    *)
      shift
      ;;
  esac
done

# Environment variable defaults
DOPETASK_VERSION="${DOPETASK_VERSION:-}"
DOPETASK_REF="${DOPETASK_REF:-}"
DOPETASK_OWNER="${DOPETASK_OWNER:-}"
DOPETASK_REPO="${DOPETASK_REPO:-}"
DOPETASK_GIT_URL="${DOPETASK_GIT_URL:-}"
DOPETASK_LOCAL_PATH="${DOPETASK_LOCAL_PATH:-}"
DOPETASK_PKG_TOKEN="${DOPETASK_PKG_TOKEN:-}"
DOPETASK_INDEX_URL="${DOPETASK_INDEX_URL:-}"
DOPETASK_EXTRA_INDEX_URL="${DOPETASK_EXTRA_INDEX_URL:-https://pypi.org/simple}"
DOPETASK_PIP="${DOPETASK_PIP:-python -m pip}"

# ============================================================================
# Utility Functions
# ============================================================================

log_info() {
  echo "[INFO] $*"
}

log_error() {
  echo "[ERROR] $*" >&2
}

log_warn() {
  echo "[WARN] $*"
}

fail() {
  log_error "$@"
  exit 1
}

check_python() {
  if ! command -v python &> /dev/null; then
    fail "Python not found. Please install Python 3.8+."
  fi
  
  if ! $DOPETASK_PIP --version &> /dev/null; then
    fail "pip not working. Check your Python installation."
  fi
}

# Allowed lockfile keys
ALLOWED_LOCKFILE_KEYS=(
  "version"
  "ref"
  "mode"
  "owner"
  "repo"
  "git_url"
  "index_url"
  "extra_index_url"
)

is_valid_lockfile_key() {
  local key="$1"
  for allowed in "${ALLOWED_LOCKFILE_KEYS[@]}"; do
    if [[ "$key" == "$allowed" ]]; then
      return 0
    fi
  done
  return 1
}

validate_version() {
  local version="$1"
  if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
    fail "Invalid version format: '$version'. Must be X.Y.Z (e.g., 0.3.0)"
  fi
}

parse_lockfile() {
  local lockfile="$1"
  
  if [[ ! -f "$lockfile" ]]; then
    log_info "Lockfile not found: $lockfile (will use env vars only)"
    return
  fi
  
  log_info "Reading lockfile: $lockfile"
  
  while IFS= read -r line || [[ -n "$line" ]]; do
    # Strip leading/trailing whitespace
    line="$(echo "$line" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
    
    # Skip blank lines
    [[ -z "$line" ]] && continue
    
    # Skip comments
    [[ "$line" =~ ^# ]] && continue
    
    # Parse key = value
    if [[ "$line" =~ ^([a-z_]+)[[:space:]]*=[[:space:]]*(.*)$ ]]; then
      local key="${BASH_REMATCH[1]}"
      local value="${BASH_REMATCH[2]}"
      
      # Trim value
      value="$(echo "$value" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
      
      # Validate key
      if ! is_valid_lockfile_key "$key"; then
        fail "Unknown key in lockfile: '$key'. Allowed keys: ${ALLOWED_LOCKFILE_KEYS[*]}"
      fi
      
      # Set env vars only if not already set
      case "$key" in
        version)
          validate_version "$value"
          [[ -z "$DOPETASK_VERSION" ]] && DOPETASK_VERSION="$value" && log_info "  version = $value (from lockfile)"
          ;;
        ref)
          [[ -z "$DOPETASK_REF" ]] && DOPETASK_REF="$value" && log_info "  ref = $value (from lockfile)"
          ;;
        mode)
          [[ "$MODE" == "auto" ]] && MODE="$value" && log_info "  mode = $value (from lockfile)"
          ;;
        owner)
          [[ -z "$DOPETASK_OWNER" ]] && DOPETASK_OWNER="$value" && log_info "  owner = $value (from lockfile)"
          ;;
        repo)
          [[ -z "$DOPETASK_REPO" ]] && DOPETASK_REPO="$value" && log_info "  repo = $value (from lockfile)"
          ;;
        git_url)
          [[ -z "$DOPETASK_GIT_URL" ]] && DOPETASK_GIT_URL="$value" && log_info "  git_url = $value (from lockfile)"
          ;;
        index_url)
          [[ -z "$DOPETASK_INDEX_URL" ]] && DOPETASK_INDEX_URL="$value" && log_info "  index_url = $value (from lockfile)"
          ;;
        extra_index_url)
          [[ "$DOPETASK_EXTRA_INDEX_URL" == "https://pypi.org/simple" ]] && DOPETASK_EXTRA_INDEX_URL="$value" && log_info "  extra_index_url = $value (from lockfile)"
          ;;
      esac
    else
      fail "Invalid lockfile syntax at line: '$line'"
    fi
  done < "$lockfile"
}

write_lockfile() {
  local lockfile="$1"
  
  log_info "Writing lockfile: $lockfile"
  
  cat > "$lockfile" <<EOF
# dopeTask install pin for this repo
# Generated by install_dopetask.sh on $(date -u +"%Y-%m-%d %H:%M:%S UTC")

# Required:
version = ${DOPETASK_VERSION:-0.0.0}

# Optional:
EOF

  if [[ -n "$DOPETASK_REF" ]]; then
    echo "ref = $DOPETASK_REF" >> "$lockfile"
  fi
  
  if [[ "$MODE" != "auto" ]]; then
    echo "mode = $MODE" >> "$lockfile"
  fi
  
  if [[ -n "$DOPETASK_OWNER" ]]; then
    echo "owner = $DOPETASK_OWNER" >> "$lockfile"
  fi
  
  if [[ -n "$DOPETASK_REPO" ]]; then
    echo "repo = $DOPETASK_REPO" >> "$lockfile"
  fi
  
  if [[ -n "$DOPETASK_GIT_URL" ]]; then
    echo "git_url = $DOPETASK_GIT_URL" >> "$lockfile"
  fi
  
  if [[ -n "$DOPETASK_INDEX_URL" ]]; then
    echo "index_url = $DOPETASK_INDEX_URL" >> "$lockfile"
  fi
  
  if [[ "$DOPETASK_EXTRA_INDEX_URL" != "https://pypi.org/simple" ]]; then
    echo "extra_index_url = $DOPETASK_EXTRA_INDEX_URL" >> "$lockfile"
  fi
  
  log_info "✅ Lockfile written successfully"
}

print_config() {
  log_info "Resolved Configuration:"
  log_info "======================="
  echo "MODE: $MODE"
  echo "DOPETASK_VERSION: ${DOPETASK_VERSION:-<not set>}"
  echo "DOPETASK_REF: ${DOPETASK_REF:-<not set>}"
  echo "DOPETASK_OWNER: ${DOPETASK_OWNER:-<not set>}"
  echo "DOPETASK_REPO: ${DOPETASK_REPO:-<not set>}"
  echo "DOPETASK_GIT_URL: ${DOPETASK_GIT_URL:-<not set>}"
  echo "DOPETASK_LOCAL_PATH: ${DOPETASK_LOCAL_PATH:-<not set>}"
  echo "DOPETASK_INDEX_URL: ${DOPETASK_INDEX_URL:-<not set>}"
  echo "DOPETASK_EXTRA_INDEX_URL: ${DOPETASK_EXTRA_INDEX_URL:-<not set>}"
  echo "DOPETASK_PKG_TOKEN: ${DOPETASK_PKG_TOKEN:+***REDACTED***}"
  echo "DOPETASK_PIP: $DOPETASK_PIP"
  echo "LOCKFILE: $LOCKFILE"
}

# ============================================================================
# Mode Selection
# ============================================================================

select_mode() {
  if [[ "$MODE" != "auto" ]]; then
    log_info "Using explicit mode: $MODE"
    return
  fi
  
  log_info "Auto-detecting install mode..."
  
  # Priority 1: GitHub Packages (if token present)
  if [[ -n "$DOPETASK_PKG_TOKEN" ]]; then
    MODE="packages"
    log_info "Detected GitHub Packages mode (token present)"
    return
  fi
  
  # Priority 2: Git (if git URL or owner+repo present)
  if [[ -n "$DOPETASK_GIT_URL" ]] || [[ -n "$DOPETASK_OWNER" && -n "$DOPETASK_REPO" ]]; then
    MODE="git"
    log_info "Detected Git mode (git URL or owner/repo present)"
    return
  fi
  
  # Priority 3: Local (if path present)
  if [[ -n "$DOPETASK_LOCAL_PATH" ]]; then
    MODE="local"
    log_info "Detected Local mode (path present)"
    return
  fi
  
  # No mode detected
  fail "Cannot auto-detect install mode. Please set one of:
  - DOPETASK_PKG_TOKEN (for GitHub Packages)
  - DOPETASK_OWNER + DOPETASK_REPO or DOPETASK_GIT_URL (for Git install)
  - DOPETASK_LOCAL_PATH (for local editable install)
  
Or explicitly specify --mode packages|git|local"
}

# ============================================================================
# Installation Functions
# ============================================================================

install_packages() {
  log_info "Installing dopeTask from GitHub Packages..."
  
  # Validate required vars
  [[ -z "$DOPETASK_VERSION" ]] && fail "DOPETASK_VERSION required for packages mode"
  [[ -z "$DOPETASK_OWNER" ]] && fail "DOPETASK_OWNER required for packages mode"
  [[ -z "$DOPETASK_PKG_TOKEN" ]] && fail "DOPETASK_PKG_TOKEN required for packages mode"
  
  # Build index URL (authenticated)
  if [[ -z "$DOPETASK_INDEX_URL" ]]; then
    DOPETASK_INDEX_URL="https://pip.pkg.github.com/${DOPETASK_OWNER}/simple"
  fi
  
  # Construct authenticated URL (DO NOT ECHO)
  local AUTH_INDEX_URL="https://${DOPETASK_PKG_TOKEN}@${DOPETASK_INDEX_URL#https://}"
  
  # Log redacted URL
  log_info "Index URL: https://***@${DOPETASK_INDEX_URL#https://}"
  log_info "Extra index: $DOPETASK_EXTRA_INDEX_URL"
  log_info "Installing: dopetask==$DOPETASK_VERSION"
  
  # Install (errors go to stderr automatically)
  $DOPETASK_PIP install \
    --index-url "$AUTH_INDEX_URL" \
    --extra-index-url "$DOPETASK_EXTRA_INDEX_URL" \
    "dopetask==$DOPETASK_VERSION"
  
  log_info "✅ Installed dopetask==$DOPETASK_VERSION from GitHub Packages"
}

install_git() {
  log_info "Installing dopeTask from Git..."
  
  # Determine ref
  local ref=""
  if [[ -n "$DOPETASK_REF" ]]; then
    ref="$DOPETASK_REF"
  elif [[ -n "$DOPETASK_VERSION" ]]; then
    ref="v${DOPETASK_VERSION}"
  else
    fail "Either DOPETASK_REF or DOPETASK_VERSION required for git mode"
  fi
  
  # Build git URL
  local git_url=""
  if [[ -n "$DOPETASK_GIT_URL" ]]; then
    git_url="$DOPETASK_GIT_URL"
  elif [[ -n "$DOPETASK_OWNER" && -n "$DOPETASK_REPO" ]]; then
    git_url="git+ssh://git@github.com/${DOPETASK_OWNER}/${DOPETASK_REPO}.git"
  else
    fail "Either DOPETASK_GIT_URL or (DOPETASK_OWNER + DOPETASK_REPO) required for git mode"
  fi
  
  log_info "Git URL: $git_url"
  log_info "Ref: $ref"
  
  # Install
  $DOPETASK_PIP install "dopetask @ ${git_url}@${ref}"
  
  log_info "✅ Installed dopetask from ${git_url}@${ref}"
}

install_local() {
  log_info "Installing dopeTask from local path..."
  
  [[ -z "$DOPETASK_LOCAL_PATH" ]] && fail "DOPETASK_LOCAL_PATH required for local mode"
  [[ ! -d "$DOPETASK_LOCAL_PATH" ]] && fail "DOPETASK_LOCAL_PATH does not exist: $DOPETASK_LOCAL_PATH"
  
  if [[ -z "$DOPETASK_VERSION" ]]; then
    log_warn "DOPETASK_VERSION not set. Local install is not pinned to a specific version."
  fi
  
  log_info "Path: $DOPETASK_LOCAL_PATH"
  
  # Install editable
  $DOPETASK_PIP install -e "$DOPETASK_LOCAL_PATH"
  
  log_info "✅ Installed dopetask editable from $DOPETASK_LOCAL_PATH"
}

# ============================================================================
# Verification
# ============================================================================

verify_install() {
  log_info "Verifying dopeTask installation..."
  
  # Smoke test: dopetask --help
  log_info "Running: dopetask --help"
  if ! dopetask --help &> /dev/null; then
    fail "dopetask --help failed. Installation may be broken."
  fi
  
  # Health check: dopetask doctor
  log_info "Running: dopetask doctor --timestamp-mode deterministic"
  if ! dopetask doctor --timestamp-mode deterministic; then
    fail "dopetask doctor failed. Installation is not healthy."
  fi
  
  log_info "✅ dopeTask installation verified successfully"
}

# ============================================================================
# Main
# ============================================================================

main() {
  log_info "dopeTask Unified Installer"
  log_info "========================"
  
  # Check prerequisites
  check_python
  
  # Load lockfile (env vars take priority)
  parse_lockfile "$LOCKFILE"
  
  # Print config if requested
  if [[ "$PRINT_CONFIG" == "true" ]]; then
    print_config
  fi
  
  # Select mode
  select_mode
  
  # Write lockfile if requested
  if [[ "$WRITE_LOCK" == "true" ]]; then
    write_lockfile "$LOCKFILE"
  fi
  
  # Verify-only mode
  if [[ "$VERIFY_ONLY" == "true" ]]; then
    log_info "Verify-only mode: skipping installation"
    verify_install
    exit 0
  fi
  
  # Install based on mode
  case "$MODE" in
    packages)
      install_packages
      ;;
    git)
      install_git
      ;;
    local)
      install_local
      ;;
    *)
      fail "Invalid mode: $MODE. Must be one of: packages, git, local, auto"
      ;;
  esac
  
  # Verify installation
  verify_install
  
  log_info "🎉 dopeTask installation complete!"
}

main "$@"
