#!/bin/bash
# Omarchy Repository Cleaner
# Removes old package versions keeping only the latest

set -e

# Source common functions
BUILD_ROOT=$(realpath "${BASH_SOURCE[0]%/*}/..")
source "$BUILD_ROOT/helpers/message-helpers.sh"
source "$BUILD_ROOT/helpers/paths.sh"
source "$BUILD_ROOT/helpers/lock-helpers.sh"

# Repository configuration
KEEP_VERSIONS=2

# Function to clean old packages
clean_packages() {
  local keep=$1
  local dry_run=$2

  print_info "Cleaning old packages (keeping $keep versions)..."

  cd "$REPO_DIR"

  # Group packages by name
  declare -A packages

  for pkg in *.pkg.tar.*; do
    [[ -f "$pkg" ]] || continue

    # Skip signature files
    [[ "$pkg" == *.sig ]] && continue

    # Extract package name (remove version and architecture)
    # Format: name-version-release-arch.pkg.tar.*
    local pkgname=$(echo "$pkg" | sed -E 's/-[0-9]+.*-(any|x86_64|i686)\.pkg\.tar\..*//')

    # Add to array
    if [[ -n "${packages[$pkgname]}" ]]; then
      packages[$pkgname]="${packages[$pkgname]} $pkg"
    else
      packages[$pkgname]="$pkg"
    fi
  done

  # Process each package group
  local total_removed=0
  local space_freed=0

  for pkgname in "${!packages[@]}"; do
    # Convert string to array and sort by modification time (newest first)
    IFS=' ' read -ra pkg_files <<<"${packages[$pkgname]}"

    # Sort by modification time
    local sorted_files=($(ls -t "${pkg_files[@]}" 2>/dev/null))
    local count=${#sorted_files[@]}

    if [[ $count -gt $keep ]]; then
      echo "  -> Processing $pkgname ($count versions found)"

      # Remove old versions
      for ((i = $keep; i < $count; i++)); do
        local file="${sorted_files[$i]}"
        local size=$(stat -c%s "$file" 2>/dev/null || echo 0)
        space_freed=$((space_freed + size))

        if [[ "$dry_run" == true ]]; then
          echo "      Would remove: $file ($(numfmt --to=iec-i --suffix=B $size))"
        else
          echo "      Removing: $file ($(numfmt --to=iec-i --suffix=B $size))"
          rm -f "$file"
          rm -f "${file}.sig" 2>/dev/null || true
        fi

        total_removed=$((total_removed + 1))
      done
    fi
  done

  # Summary
  if [[ $total_removed -gt 0 ]]; then
    if [[ "$dry_run" == true ]]; then
      echo "  -> Would remove $total_removed old package(s)"
      echo "  -> Would free $(numfmt --to=iec-i --suffix=B $space_freed)"
    else
      echo "  -> Removed $total_removed old package(s)"
      echo "  -> Freed $(numfmt --to=iec-i --suffix=B $space_freed)"
    fi
  else
    echo "  -> No old packages to remove"
  fi
}

# Function to remove all packages
remove_all_packages() {
  local dry_run=$1

  print_error "WARNING: Removing ALL packages from repository!"

  if [[ "$dry_run" != true ]]; then
    read -p "Are you sure? Type 'yes' to confirm: " confirm
    if [[ "$confirm" != "yes" ]]; then
      print_warning "Cancelled."
      exit 0
    fi
  fi

  cd "$REPO_DIR"

  local count=$(ls -1 *.pkg.tar.* 2>/dev/null | wc -l)

  if [[ $count -eq 0 ]]; then
    print_warning "No packages found to remove"
    return
  fi

  if [[ "$dry_run" == true ]]; then
    print_warning "Would remove $count package(s):"
    ls -1 *.pkg.tar.* 2>/dev/null | while read -r pkg; do
      echo "  - $pkg"
    done
  else
    rm -f *.pkg.tar.*
    rm -f *.db* *.files*
    echo "Removed $count package(s) and database files"
  fi
}

# Function to show repository disk usage
show_disk_usage() {
  print_info "Repository Disk Usage:"

  cd "$REPO_DIR"

  local total_size=$(du -sh . 2>/dev/null | cut -f1)
  local package_count=$(ls -1 *.pkg.tar.* 2>/dev/null | grep -v '\.sig$' | wc -l)

  echo "  -> Total size: $total_size"
  echo "  -> Package count: $package_count"

  if [[ $package_count -gt 0 ]]; then
    local avg_size=$(du -b *.pkg.tar.* 2>/dev/null | awk '{sum+=$1; count++} END {printf "%.0f", sum/count}')
    echo "  -> Average package size: $(numfmt --to=iec-i --suffix=B $avg_size 2>/dev/null || echo "N/A")"
  fi
}

# Main execution
main() {
  print_header "Omarchy Repository Cleaner"
  
  # Parse command line arguments
  DRY_RUN=false
  REMOVE_ALL=false
  SHOW_USAGE=false

  while [[ $# -gt 0 ]]; do
    case $1 in
    --arch)
      ARCH="$2"
      update_arch_paths
      shift 2
      ;;
    --mirror)
      MIRROR="$2"
      require_valid_mirror "$MIRROR"
      update_arch_paths
      shift 2
      ;;
    --keep)
      KEEP_VERSIONS="$2"
      shift 2
      ;;
    --dry-run)
      DRY_RUN=true
      shift
      ;;
    --all)
      REMOVE_ALL=true
      shift
      ;;
    --usage)
      SHOW_USAGE=true
      shift
      ;;
    -h | --help)
      echo "Usage: $0 [OPTIONS]"
      echo ""
      echo "Options:"
      echo "  --arch <arch>      Target architecture (x86_64 or aarch64, default: x86_64)"
      echo "  --mirror <mirror>  Mirror to use (edge, rc, or stable, default: edge)"
      echo "  --keep N           Keep N versions of each package (default: 2)"
      echo "  --dry-run          Preview what would be removed without removing"
      echo "  --all              Remove ALL packages (dangerous!)"
      echo "  --usage            Show disk usage statistics"
      echo "  -h, --help         Show this help message"
      echo ""
      echo "Examples:"
      echo "  $0                    # Keep 2 versions (default)"
      echo "  $0 --keep 3          # Keep 3 versions"
      echo "  $0 --dry-run         # Preview cleanup"
      echo "  $0 --all --dry-run   # Preview complete removal"
      exit 0
      ;;
    *)
      print_error "Unknown option: $1"
      exit 1
      ;;
    esac
  done

  print_info "Mirror: $MIRROR"
  print_info "Architecture: $ARCH"
  print_info "Repository: $REPO_DIR"
  echo ""

  # Validate keep versions
  if ! [[ "$KEEP_VERSIONS" =~ ^[0-9]+$ ]] || [[ "$KEEP_VERSIONS" -lt 1 ]]; then
    print_error "Error: --keep must be a positive integer"
    exit 1
  fi

  # Show dry run notice
  if [[ "$DRY_RUN" == true ]]; then
    print_warning "DRY RUN MODE - No changes will be made"
  fi

  if [[ "$DRY_RUN" != true && "$SHOW_USAGE" != true ]]; then
    acquire_release_lock || exit 1
  fi

  # Execute based on options
  if [[ "$SHOW_USAGE" == true ]]; then
    show_disk_usage
  elif [[ "$REMOVE_ALL" == true ]]; then
    remove_all_packages "$DRY_RUN"
  else
    clean_packages "$KEEP_VERSIONS" "$DRY_RUN"

    # Update database after cleaning (unless dry run)
    if [[ "$DRY_RUN" != true ]]; then
      # Moved to release workflow
      :
    fi

    show_disk_usage
  fi
}

# Run main function
main "$@"
