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

REPO_ROOT=$(git rev-parse --show-toplevel)
SCRIPT_DIR="$REPO_ROOT/scripts"
source "$SCRIPT_DIR/container_clang_format.sh"

usage() {
    cat <<'EOF'
Usage:
  scripts/format [--check] [--] [files...]
  scripts/format                     # format all tracked C/C++ files
  scripts/format foo.cpp bar.hpp
  scripts/format --check             # check formatting (no changes), all tracked files
  scripts/format --check foo.cpp

Options:
  --check   Don't modify files; fail if formatting differs (clang-format --dry-run -Werror)
  -h,--help Show help
EOF
}

CHECK=0
args=()

while [[ $# -gt 0 ]]; do
  case "$1" in
    --check) CHECK=1; shift ;;
    --) shift; args+=("$@"); break ;;
    -h|--help) usage; exit 0 ;;
    *) args+=("$1"); shift ;;
  esac
done

# Collect files to format:
# - No file args: all tracked C/C++ files.
# - With file args: normalize each to repo-root–relative.
files=()
if [[ ${#args[@]} -eq 0 ]]; then
    # All tracked files
    readarray -t files < <(
        git -C "$REPO_ROOT" ls-files | grep -E '\.(cpp|hpp|cc|h|cxx|hxx)$' || true
    )
else
    for arg in "${args[@]}"; do
        # If tracked, get repo-relative path directly
        if rel="$(git -C "$REPO_ROOT" ls-files --full-name -- "$arg" 2>/dev/null)"; then
            if [ -n "$rel" ]; then files+=("$rel"); continue; fi
        fi
        # Untracked: resolve absolute, then strip repo root prefix
        dirpart="${arg%/*}"
        basepart="${arg##*/}"
        if [ "$dirpart" = "$arg" ]; then
            # no slash in arg (just a filename)
            dirpart="."
        fi
        if absdir="$(cd "$dirpart" 2>/dev/null && pwd -P)"; then
            abspath="$absdir/$basepart"
            case "$abspath" in
                "$REPO_ROOT"/*)
                    rel="${abspath#"$REPO_ROOT"/}"
                    files+=("$rel")
                    ;;
                *)
                    echo "warning: '$arg' is not inside the repo ($REPO_ROOT) — skipping" >&2
                    ;;
            esac
        else
          echo "warning: cannot resolve '$arg' — skipping" >&2
        fi
    done
fi

if [ "${#files[@]}" -eq 0 ]; then
    echo "No files to format."
    exit 0
fi

# clang-format args (fix vs check)
if [[ "$CHECK" -eq 1 ]]; then
    CF_ARGS=(--dry-run -Werror --style=file)
else
    CF_ARGS=(-i --style=file)
fi

# Submit batch to the container
submit_batch() {
    local -a batch=("$@")
    [[ ${#batch[@]} -eq 0 ]] && return 0

    $OCIRUN run --rm $USER_FLAG \
        -v "$REPO_ROOT":/work -w /work \
        "$IMAGE_TAG" "${CF_ARGS[@]}" "${batch[@]}"
}

BATCH_SIZE=100
FAILED=0

# Process files in batches
for ((i=0; i<${#files[@]}; i+=BATCH_SIZE)); do
    batch=( "${files[@]:i:BATCH_SIZE}" )
    submit_batch "${batch[@]}" || FAILED=1
done

if [[ "$CHECK" -eq 1 ]]; then
    if [[ "$FAILED" -ne 0 ]]; then
        echo "Clang-format check failed. Run: scripts/format <files> (without --check) to fix."
        exit 1
    fi
    echo "Clang-format check passed."
else
    echo "Formatting complete."
fi
