#!/bin/bash
# sync-music — manually sync ~/Music into the beets library on the Unraid NAS.
#
#   sync-music          # shell alias -> ~/.local/bin/sync-music
#
# How it works:
#   1. Ensures the NAS SMB share is mounted at /Volumes/data (uses your keychain
#      credentials; falls back to a clear error if it can't mount).
#   2. Imports every audio file anywhere under ~/Music (recursively) into beets
#      via `beet import --noautotag --move --singletons`, which moves each file
#      into the library and removes it from ~/Music. Files already in the
#      library are skipped (left in place). Safe to re-run any time.
#
# Why a manual script (not the old daemon)? The daemon kept dying because
# launchd/WezTerm spawn a minimal PATH that lacks /opt/homebrew/bin (where
# `beet` lives). Running this script yourself in your own shell avoids that.
#
# Configure your server below.

NAS_HOST="unraid.local"
NAS_SHARE="data"
NAS_USER="backup"
MOUNT_POINT="/Volumes/data"
LIBRARY_DIR="$MOUNT_POINT/media/music"

WATCH_DIR="$HOME/Music"
LOG_FILE="$HOME/Library/Logs/beet-watch.log"

AUDIO_EXT="flac|mp3|m4a|aac|wav|alac|ogg|wma|opus|aiff|aif"

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"; }

# --- locate beet — works whether it comes from nix profile or Homebrew ---
BEET="$(command -v beet 2>/dev/null || true)"
if [ ! -x "$BEET" ]; then
    echo "ERROR: beet not found." >&2
    exit 1
fi

# --- 1. ensure the NAS is mounted ---
if [ ! -d "$MOUNT_POINT" ]; then
    log "NAS not mounted; mounting smb://$NAS_USER@$NAS_HOST/$NAS_SHARE ..."
    open "smb://$NAS_USER@$NAS_HOST/$NAS_SHARE" 2>/dev/null || true
    for _ in $(seq 1 30); do
        [ -d "$MOUNT_POINT" ] && break
        sleep 1
    done
fi
if [ ! -d "$MOUNT_POINT" ]; then
    echo "ERROR: $MOUNT_POINT is not mounted."                          >&2
    echo "  Mount it, then re-run:"                                      >&2
    echo "    open smb://$NAS_USER@$NAS_HOST/$NAS_SHARE"                 >&2
    exit 1
fi

# --- 2. import every (finished) audio file in ~/Music ---
# NOTE: We do NOT clear the beets DB. Files are imported as singletons
# (--singletons) so beets never matches them against existing albums in the
# library, which is what previously made it delete the prior tracks of an
# album via the 'R' (remove old) prompt. The DB lives at
#   $LIBRARY_DIR/beets/beets_library.db  (per ~/.config/beets/config.yaml).
log "sync-music: scanning $WATCH_DIR -> $LIBRARY_DIR"

# Recursively collect every audio file under $WATCH_DIR.
files=()
while IFS= read -r -d '' f; do
    [[ "${f##*.}" =~ ^($AUDIO_EXT)$ ]] && files+=("$f")
done < <(find "$WATCH_DIR" -type f -print0 2>/dev/null)

total=${#files[@]}
log "Found $total audio file(s)."

ok=0; skipped=0; failed=0
for f in "${files[@]}"; do
    # skip files still being written (size must be stable for 1s)
    s1=$(stat -f%z "$f" 2>/dev/null || echo 0)
    sleep 1
    s2=$(stat -f%z "$f" 2>/dev/null || echo 0)
    if [ "$s1" != "$s2" ]; then
        log "  still writing, skipping: $(basename "$f")"
        skipped=$((skipped + 1))
        continue
    fi

    bn=$(basename "$f")

    # Pre-check: has beets already imported this file? Match by exact path, or
    # by a title guess derived from the filename ("03 - Artist - Title").
    existing="$(beet ls --path "$f" 2>/dev/null || true)"
    stripped="$(echo "$bn" | sed 's/\.[A-Za-z0-9]*$//' | sed -E 's/^[0-9]+ - [^ -]+ - //' )"
    if [ -n "$existing" ] || [ -n "$(beet ls "$stripped" 2>/dev/null || true)" ]; then
        log "  already in library (skipped): $bn"
        ok=$((ok + 1))
        continue
    fi

    log "  importing: $bn"
    # Import as a singleton so beets never offers to "remove old" and delete
    # other tracks from the same album. Reads confirm from stdin; with no
    # matches there is no prompt, and if one does appear 'S' (=skip new) is the
    # safe default that never deletes anything.
    out=$(printf 'S\n' | "$BEET" import --noautotag --move --singletons "$f" 2>&1)
    rc=$?
    if [ $rc -eq 0 ] && [ ! -f "$f" ]; then
        log "  moved into library: $bn"
        ok=$((ok + 1))
    elif [ $rc -eq 0 ]; then
        # Import succeeded but source still exists — beets kept new file (didn't remove old)
        if echo "$out" | grep -qi 'keep'; then
            log "  kept existing, source remains: $bn"
            ok=$((ok + 1))
        else
            log "  IMPORTED but source still present (rc=0): $bn :: $(printf '%s' "$out" | head -c 200)"
            failed=$((failed + 1))
        fi
    else
        log "  FAILED (rc=$rc): $bn :: $(printf '%s' "$out" | head -c 200)"
        failed=$((failed + 1))
    fi
done

log "sync-music complete: $total considered, ok=$ok, still-writing-skipped=$skipped, failed=$failed"
[ "$failed" -gt 0 ] && log "  some imports failed; fix and re-run."
exit 0
