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

# update-nix-file.sh - Atomically update OpenCode version and sha256 in Nix package
#
# Usage: update-nix-file.sh <version> <sha256> [--dotfiles PATH] [--dry-run]
#
# Example: update-nix-file.sh 1.0.58 sha256-ABC123... --dry-run
#
# Options:
#   --dotfiles PATH  Path to dotfiles repo (default: ~/proj/dotfiles)
#   --dry-run        Show changes without modifying file

VERSION=""
SHA256=""
DOTFILES_PATH="${HOME}/proj/dotfiles"
DRY_RUN=false

# Parse arguments
while [[ $# -gt 0 ]]; do
  case "$1" in
    --dotfiles)
      DOTFILES_PATH="$2"
      shift 2
      ;;
    --dry-run)
      DRY_RUN=true
      shift
      ;;
    *)
      if [[ -z "$VERSION" ]]; then
        VERSION="$1"
        shift
      elif [[ -z "$SHA256" ]]; then
        SHA256="$1"
        shift
      else
        echo "Error: Unknown argument '$1'" >&2
        echo "Usage: $0 <version> <sha256> [--dotfiles PATH] [--dry-run]" >&2
        exit 1
      fi
      ;;
  esac
done

# Validate required arguments
if [[ -z "$VERSION" || -z "$SHA256" ]]; then
  echo "Error: Missing required arguments" >&2
  echo "Usage: $0 <version> <sha256> [--dotfiles PATH] [--dry-run]" >&2
  exit 1
fi

# Validate version format
if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
  echo "Error: Invalid version format '$VERSION' (expected X.Y.Z)" >&2
  exit 1
fi

# Validate SHA256 format (SRI)
if ! echo "$SHA256" | grep -qE '^sha256-[A-Za-z0-9+/]+=*$'; then
  echo "Error: Invalid SHA256 format '$SHA256' (expected sha256-...)" >&2
  exit 1
fi

# Check dependencies
for cmd in sed grep; do
  if ! command -v "$cmd" >/dev/null 2>&1; then
    echo "Error: Required command '$cmd' not found" >&2
    exit 1
  fi
done

# Validate Nix file exists
NIX_FILE="${DOTFILES_PATH}/pkgs/opencode/default.nix"
if [[ ! -f "$NIX_FILE" ]]; then
  echo "Error: Nix file not found at $NIX_FILE" >&2
  exit 1
fi

# Validate that patterns exist in file (prevents no-op edits)
if ! grep -qE 'version\s*=\s*"[^"]*"' "$NIX_FILE"; then
  echo "Error: Could not find 'version = \"...\"' pattern in $NIX_FILE" >&2
  exit 1
fi

if ! grep -qE 'sha256\s*=\s*"[^"]*"' "$NIX_FILE"; then
  echo "Error: Could not find 'sha256 = \"...\"' pattern in $NIX_FILE" >&2
  exit 1
fi

# Dry-run: show diff without modifying
if [[ "$DRY_RUN" == true ]]; then
  echo "=== Dry-run mode: showing changes ===" >&2
  echo "" >&2
  
  # Show current values
  CURRENT_VERSION=$(grep -oP 'version\s*=\s*"\K[^"]+' "$NIX_FILE")
  CURRENT_SHA256=$(grep -oP 'sha256\s*=\s*"\K[^"]+' "$NIX_FILE")
  
  echo "Current version: $CURRENT_VERSION" >&2
  echo "New version:     $VERSION" >&2
  echo "" >&2
  echo "Current sha256:  $CURRENT_SHA256" >&2
  echo "New sha256:      $SHA256" >&2
  echo "" >&2
  
  # Show diff
  echo "=== File diff ===" >&2
  sed -e "s/version = \"[^\"]*\"/version = \"$VERSION\"/" \
      -e "s/sha256 = \"[^\"]*\"/sha256 = \"$SHA256\"/" \
      "$NIX_FILE" | diff -u --color=auto "$NIX_FILE" - || true
  
  exit 0
fi

# Perform atomic update
TEMP_FILE=$(mktemp "${NIX_FILE}.XXXXXX")
trap 'rm -f "$TEMP_FILE"' EXIT

if ! sed \
  -e "s/version = \"[^\"]*\"/version = \"$VERSION\"/" \
  -e "s/sha256 = \"[^\"]*\"/sha256 = \"$SHA256\"/" \
  "$NIX_FILE" > "$TEMP_FILE"; then
  echo "Error: failed to generate updated Nix file" >&2
  exit 1
fi

# Basic validation: check if it's not empty and contains expected values
if [[ ! -s "$TEMP_FILE" ]]; then
  echo "Error: Generated file is empty" >&2
  exit 1
fi

if ! grep -q "version = \"$VERSION\"" "$TEMP_FILE" || ! grep -q "sha256 = \"$SHA256\"" "$TEMP_FILE"; then
  echo "Error: Generated file validation failed (expected patterns not found)" >&2
  exit 1
fi

# Atomic move
mv "$TEMP_FILE" "$NIX_FILE"
trap - EXIT

# Verify update succeeded (extra safety check)
UPDATED_VERSION=$(grep -oP 'version\s*=\s*"\K[^"]+' "$NIX_FILE")
UPDATED_SHA256=$(grep -oP 'sha256\s*=\s*"\K[^"]+' "$NIX_FILE")

if [[ "$UPDATED_VERSION" != "$VERSION" ]]; then
  echo "Error: Version update failed (expected $VERSION, got $UPDATED_VERSION)" >&2
  exit 1
fi

if [[ "$UPDATED_SHA256" != "$SHA256" ]]; then
  echo "Error: SHA256 update failed (expected $SHA256, got $UPDATED_SHA256)" >&2
  exit 1
fi

echo "✓ Updated $NIX_FILE"
echo "  version: $UPDATED_VERSION"
echo "  sha256:  $UPDATED_SHA256"
