#!/usr/bin/env sh

set -e

# Ensure consistent sorting for comm
export LC_ALL=C

# --- Usage / Help ---
if [ "$1" = "--usage" ]; then
    echo "Interactively manage the Aico context using git ls-files and fzf (add/drop files with optional bat preview)."
    exit 0
fi

# --- Dependency checks ---

if ! command -v git >/dev/null 2>&1; then
    echo "Error: git is required for manage-context (to list project files)." >&2
    exit 1
fi

if ! command -v fzf >/dev/null 2>&1; then
    echo "Error: fzf is required for manage-context. Please install fzf to use this addon." >&2
    exit 1
fi

if ! command -v jq >/dev/null 2>&1; then
    echo "Error: jq is required for manage-context. Please install jq to use this addon." >&2
    exit 1
fi

# Optional pretty preview: bat if available, otherwise plain text preview
if command -v bat >/dev/null 2>&1; then
    PREVIEW_CMD='bat --color=always --style=numbers --line-range=:200 {}'
else
    # Fallback: show first 200 lines with basic numbering
    PREVIEW_CMD='nl -ba {} | sed -n "1,200p"'
fi

# --- Determine repo root (for nicer relative paths) ---

if git rev-parse --show-toplevel >/dev/null 2>&1; then
    REPO_ROOT="$(git rev-parse --show-toplevel)"
    cd "$REPO_ROOT"
fi

# --- Build candidate file list from git ---
# We include both tracked and untracked (but unignored) files, mirroring fd-like behavior.

# --- Build candidate file list from git and existing context ---
TRACKED="$(git ls-files)"
UNTRACKED="$(git ls-files --others --exclude-standard)"

# Discover current context files via status --json command
CURRENT_CONTEXT_ORIGINAL="$(aico status --json | jq -r '.context_files[]' | sort -u)"

# Combine git-managed files with current context files.
ALL_CANDIDATES="$(
  printf "%s\n" "$TRACKED" "$UNTRACKED" "$CURRENT_CONTEXT_ORIGINAL" \
  | grep . \
  | sort -u
)"

if [ -z "$ALL_CANDIDATES" ]; then
    echo "No files found to manage in context." >&2
    exit 0
fi

# --- Reorder candidates for fzf: context files first, then the rest ---
TMP_ALL=$(mktemp -t aico_manage_all.XXXXXX)
TMP_CUR=$(mktemp -t aico_manage_cur.XXXXXX)
[ -n "$ALL_CANDIDATES" ] && printf "%s\n" "$ALL_CANDIDATES" > "$TMP_ALL"
[ -n "$CURRENT_CONTEXT_ORIGINAL" ] && printf "%s\n" "$CURRENT_CONTEXT_ORIGINAL" > "$TMP_CUR"

# 1. Files in both ALL_CANDIDATES and CURRENT_CONTEXT_ORIGINAL (already in context)
IN_CONTEXT_FILES="$(comm -12 "$TMP_ALL" "$TMP_CUR" | grep . || true)"

# 2. Files in ALL_CANDIDATES but NOT in CURRENT_CONTEXT_ORIGINAL (not in context yet)
NOT_IN_CONTEXT_FILES="$(comm -23 "$TMP_ALL" "$TMP_CUR" | grep . || true)"

# Cleanup temps
rm -f "$TMP_ALL" "$TMP_CUR"

# Calculate the number of files in context to pre-select them
NUM_IN_CONTEXT=$(printf "%s\n" "$IN_CONTEXT_FILES" | sed '/^$/d' | wc -l)

# --- Interactive selection via fzf ---
SELECT_SEQUENCE=""
i=$NUM_IN_CONTEXT
while [ "$i" -gt 0 ]; do
    SELECT_SEQUENCE="$SELECT_SEQUENCE $i"
    i=$((i - 1))
done

# FZF options (using positional parameters for POSIX robustness)
set -- --sync --multi --preview "$PREVIEW_CMD" \
  --header '== In Context (pre-selected) ==  |  [alt-c] clear all  [alt-o] only context' \
  --bind 'alt-c:clear-multi' \
  --bind "load:transform:printf '+clear-multi'; printf '+pos(%d)+select' $SELECT_SEQUENCE" \
  --bind 'alt-o:clear-query+search()+bg-transform(printf "trigger(load)")'

SELECTED_FILES="$(
  (printf "%s\n" "$IN_CONTEXT_FILES"; printf "%s\n" "$NOT_IN_CONTEXT_FILES") \
    | grep . \
    | fzf "$@"
)"

if [ -z "$SELECTED_FILES" ]; then
    # User cancelled or selected nothing
    exit 0
fi

# --- Compute delta between selected files and current context ---

# Normalize to one-per-line sets
NEW_SELECTION="$(printf "%s\n" "$SELECTED_FILES" | sort -u)"
CURRENT_CONTEXT_SORTED="$(printf "%s\n" "$CURRENT_CONTEXT_ORIGINAL" | sort -u)"

TMP_NEW=$(mktemp -t aico_manage_new.XXXXXX)
TMP_CUR_SORTED=$(mktemp -t aico_manage_cur_sorted.XXXXXX)
[ -n "$NEW_SELECTION" ] && printf "%s\n" "$NEW_SELECTION" > "$TMP_NEW"
[ -n "$CURRENT_CONTEXT_SORTED" ] && printf "%s\n" "$CURRENT_CONTEXT_SORTED" > "$TMP_CUR_SORTED"

# Files to add: in NEW_SELECTION but not in CURRENT_CONTEXT
TO_ADD="$(comm -23 "$TMP_NEW" "$TMP_CUR_SORTED" | grep . || true)"

# Files to drop: in CURRENT_CONTEXT but not in NEW_SELECTION
TO_DROP="$(comm -13 "$TMP_NEW" "$TMP_CUR_SORTED" | grep . || true)"

rm -f "$TMP_NEW" "$TMP_CUR_SORTED"

# --- Apply add/drop operations via aico ---

CHANGED=0

if [ -n "$TO_ADD" ]; then
  CHANGED=1
  printf "%s\n" "$TO_ADD" | xargs -t aico add
fi

if [ -n "$TO_DROP" ]; then
  CHANGED=1
  printf "%s\n" "$TO_DROP" | xargs -t aico drop
fi

if [ "$CHANGED" -eq 0 ]; then
  echo "Context unchanged." >&2
fi
