#!/usr/bin/env bash
# resize-tokenizer-inplace.sh
#
# Resize images in place under SRC, preserving each original as
#   <name>.original.<ext>
# in the same directory. Foundry's existing <img src> URLs keep working
# (they still point at <name>.<ext>) but now serve the resized version.
#
# Idempotent: if <name>.original.<ext> already exists, the script uses
# that as the source of truth and just regenerates <name>.<ext>. Running
# the script twice with the same TARGET_SIZE is a no-op (skipped via
# "already small enough" check on the destination).
#
# Usage:
#   ./resize-tokenizer-inplace.sh                       # default settings
#   ./resize-tokenizer-inplace.sh --size 600            # different size
#   ./resize-tokenizer-inplace.sh --dry-run             # show what would change
#   ./resize-tokenizer-inplace.sh --restore             # roll back: move
#                                                       # .original copies back
#
# Requires: ImageMagick (magick / convert / identify)

set -euo pipefail

# ---------- Config ----------
SRC="${SRC:-./foundry/data/Data/tokenizer/npc-avatars}"
TARGET_SIZE="${TARGET_SIZE:-512}"        # max dimension (longest side)
QUALITY="${QUALITY:-85}"                 # webp/jpeg quality
ORIGINAL_SUFFIX="original"               # so foo.webp -> foo.original.webp
EXTENSIONS=(webp png jpg jpeg)           # file types to process
DRY_RUN=0
RESTORE=0

# ---------- Arg parsing ----------
while [[ $# -gt 0 ]]; do
    case "$1" in
        --size)     TARGET_SIZE="$2"; shift 2 ;;
        --quality)  QUALITY="$2"; shift 2 ;;
        --src)      SRC="$2"; shift 2 ;;
        --dry-run)  DRY_RUN=1; shift ;;
        --restore)  RESTORE=1; shift ;;
        --help|-h)
            sed -n '2,/^$/p' "$0" | sed 's/^# \{0,1\}//'
            exit 0
            ;;
        *)
            echo "Unknown argument: $1" >&2
            exit 1
            ;;
    esac
done

if [[ ! -d "$SRC" ]]; then
    echo "Source directory does not exist: $SRC" >&2
    exit 1
fi

# ---------- Tool detection ----------
if command -v magick >/dev/null; then
    MAGICK="magick"
elif command -v convert >/dev/null; then
    MAGICK="convert"
else
    echo "ImageMagick not found (need 'magick' or 'convert')." >&2
    exit 1
fi
IDENTIFY="$(command -v identify || true)"

# ---------- Build find pattern ----------
find_args=()
for i in "${!EXTENSIONS[@]}"; do
    if [[ $i -gt 0 ]]; then find_args+=("-o"); fi
    find_args+=("-iname" "*.${EXTENSIONS[$i]}")
done

# ---------- Counters ----------
total=0
resized=0
skipped_already_small=0
skipped_already_processed=0
restored=0
errors=0

log()  { printf '%s\n' "$*"; }
warn() { printf 'WARN: %s\n' "$*" >&2; }
err()  { printf 'ERR : %s\n' "$*" >&2; }

# Replace the last ".<ext>" with ".${ORIGINAL_SUFFIX}.<ext>"
backup_path_for() {
    local file="$1"
    local dir base ext
    dir="$(dirname "$file")"
    base="$(basename "$file")"
    ext="${base##*.}"
    base="${base%.*}"
    printf '%s/%s.%s.%s' "$dir" "$base" "$ORIGINAL_SUFFIX" "$ext"
}

# Returns 0 if the file path already contains .${ORIGINAL_SUFFIX}. (a backup)
is_backup() {
    local f="$1"
    [[ "$f" == *.${ORIGINAL_SUFFIX}.* ]]
}

# Read longest side via ImageMagick. Returns "0" on failure.
longest_side() {
    local f="$1"
    if [[ -z "$IDENTIFY" ]]; then echo 0; return; fi
    "$IDENTIFY" -format '%[fx:max(w,h)]' "$f" 2>/dev/null || echo 0
}

# ---------- Restore mode ----------
if [[ "$RESTORE" == "1" ]]; then
    log "RESTORE mode: moving *.${ORIGINAL_SUFFIX}.* back to their original names under $SRC"
    while IFS= read -r -d '' backup; do
        # backup looks like: /.../foo.original.webp
        # target name:        /.../foo.webp
        target="${backup/.${ORIGINAL_SUFFIX}./.}"
        if [[ "$DRY_RUN" == "1" ]]; then
            log "  would: mv \"$backup\" -> \"$target\""
        else
            mv -f -- "$backup" "$target"
            restored=$((restored + 1))
        fi
    done < <(find "$SRC" -type f \( "${find_args[@]}" \) -name "*.${ORIGINAL_SUFFIX}.*" -print0)
    log "Restored: $restored files"
    exit 0
fi

# ---------- Resize loop ----------
log "Resizing images under $SRC to max dimension ${TARGET_SIZE}px (quality $QUALITY)"
log "Original files will be preserved as <name>.${ORIGINAL_SUFFIX}.<ext>"
[[ "$DRY_RUN" == "1" ]] && log "(dry-run: no files will be modified)"
log ""

while IFS= read -r -d '' file; do
    total=$((total + 1))

    # Skip files that are themselves the backup copy
    if is_backup "$file"; then continue; fi

    backup="$(backup_path_for "$file")"

    # Source-of-truth: prefer the backup if present (idempotent re-runs)
    if [[ -f "$backup" ]]; then
        source_file="$backup"
        already_processed=1
    else
        source_file="$file"
        already_processed=0
    fi

    # If destination is already small enough, skip
    cur_size="$(longest_side "$file")"
    if [[ "$already_processed" == "1" && "$cur_size" -gt 0 && "$cur_size" -le "$TARGET_SIZE" ]]; then
        skipped_already_processed=$((skipped_already_processed + 1))
        continue
    fi

    # If original is already small enough AND no backup yet, skip — no point shrinking
    src_size="$(longest_side "$source_file")"
    if [[ "$already_processed" == "0" && "$src_size" -gt 0 && "$src_size" -le "$TARGET_SIZE" ]]; then
        skipped_already_small=$((skipped_already_small + 1))
        continue
    fi

    log "  $file (${src_size}px -> ${TARGET_SIZE}px)"

    if [[ "$DRY_RUN" == "1" ]]; then
        continue
    fi

    # Move original aside if we haven't already
    if [[ "$already_processed" == "0" ]]; then
        if ! mv -n -- "$file" "$backup"; then
            err "Could not back up $file -> $backup"
            errors=$((errors + 1))
            continue
        fi
    fi

    # Resize: backup -> original path
    if ! "$MAGICK" "$backup" \
            -resize "${TARGET_SIZE}x${TARGET_SIZE}>" \
            -quality "$QUALITY" \
            "$file"; then
        err "Resize failed for $file. Restoring original."
        mv -f -- "$backup" "$file" || true
        errors=$((errors + 1))
        continue
    fi

    resized=$((resized + 1))
done < <(find "$SRC" -type f \( "${find_args[@]}" \) -print0)

log ""
log "Summary:"
log "  scanned:                  $total"
log "  resized:                  $resized"
log "  skipped (already small):  $skipped_already_small"
log "  skipped (already processed, dest small enough): $skipped_already_processed"
log "  errors:                   $errors"
[[ "$DRY_RUN" == "1" ]] && log "  (dry-run: no files modified)"
