#!/bin/bash
# ==============================================================================================
# =============================== Emby → Radarr Sync ==========================================
# ==============================================================================================
#
# PURPOSE
# ─────────────────────────────────────────────────────────────────────────────
# One-shot tool. Finds movies present in Emby that are not tracked in Radarr
# and adds them. No scoring — if it's in your library, Radarr should monitor it.
#
# Intended as a bootstrap / catch-up tool. Run after Radarr setup, after a
# database wipe, or any time you suspect gaps between your library and Radarr.
#
# Cache-first Radarr library fetch (2026-07-17) — comes from the shared tracked-data cache
# via arr_get_tracked_data(), fresh (kept warm every 30min by arr_cache_prefill.sh), live
# fetch as fallback.
#
# ==============================================================================================
# OPERATIONAL MODEL
# ==============================================================================================
#
#   1. Fetch all Movie items from Emby (with TMDB provider IDs)
#   2. Fetch current Radarr library (indexed by TMDB ID and title)
#   3. For each Emby movie not in Radarr → add to Radarr
#
# Matching prefers TMDB ID when available (immune to title differences),
# falling back to case-insensitive title comparison.
#
# ==============================================================================================
# DESIGN PRINCIPLES
# ==============================================================================================
#
# Add-Only, Never Remove
#   The tool only adds movies the arr is missing. It never deletes or unmonitors anything,
#   so the worst outcome of a bad match is an extra tracked entry — trivially reversible —
#   rather than lost tracking on something already curated.
#
# Library Membership Is the Whole Criterion
#   No scoring, no thresholds, no metadata quality gates. If it is in Emby, the arr should
#   know about it. This is deliberately not a discovery tool; the playback_aware_* scripts
#   own that job and its judgement calls.
#
# Provider ID Over Title
#   Matching prefers the TMDB ID and falls back to case-insensitive title only when the ID
#   is absent. Titles differ across sources by punctuation, year suffixes and articles;
#   matching on them alone would re-add things the arr already tracks.
#
# Cache-First Read
#   The arr library comes from the shared tracked-data cache, kept warm by
#   arr_cache_prefill.sh, with a live fetch as fallback. One read regardless of library size.
#
# ==============================================================================================
# OPERATIONAL SAFEGUARDS
# ==============================================================================================
#
# Root Required
#   acquire_lock requires root. Script exits cleanly if not root.
#
# Dry-Run Mode
#   --dry-run shows all movies that would be added without making any Radarr API calls.
#   Always run first when closing the gap after a fresh Radarr install or database wipe.
#
# Add-Only
#   Only adds movies to Radarr. Items already tracked by TMDB ID or title are skipped
#   without modification. Safe to run multiple times — the second run finds nothing to add.
#
# ==============================================================================================
# CONFIGURATION
# ==============================================================================================
#
#   RADARR_EMBY_LIBRARIES                      — Emby library names to scan (master.conf); empty = all libraries
#   HOST*_RADARR_URL / HOST*_RADARR_API_KEY    — Radarr connection (aliased by detect_hosts)
#   HOST*_EMBY_URL   / HOST*_EMBY_API_KEY      — Emby connection (aliased by detect_hosts)
#
# ==============================================================================================
# RUNTIME MODES
# ==============================================================================================
#
#   emby_to_radarr_sync.sh             — add all untracked movies to Radarr
#   emby_to_radarr_sync.sh --dry-run   — show what would be added, no changes
#   emby_to_radarr_sync.sh --log       — verbose output
#
# ==============================================================================================

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

source "$SCRIPT_DIR/../load_config.sh"

parse_args "$@"

if [[ "$EUID" -ne 0 ]]; then
    error "Must be run as root"
    exit 1
fi

acquire_lock
detect_hosts

if ! command -v jq >/dev/null 2>&1; then
    error "jq not installed"
    exit 1
fi

if [[ -z "${EMBY_URL:-}" || -z "${EMBY_API_KEY:-}" ]]; then
    error "EMBY_URL / EMBY_API_KEY not configured — check host*.conf"
    exit 1
fi

if [[ -z "${RADARR_URL:-}" || -z "${RADARR_API_KEY:-}" ]]; then
    error "RADARR_URL / RADARR_API_KEY not configured — check host*.conf"
    exit 1
fi

log "$ICON_GEAR Config: emby=${EMBY_URL} radarr=${RADARR_URL}"
[[ "$DRY_RUN" == true ]] && warn "DRY RUN — no movies will be added to Radarr"

# ==============================================================================================
# ── API HELPERS ───────────────────────────────────────────────────────────────────────────────
# ==============================================================================================


_radarr_get() {
    curl -sf --max-time 30 \
        -H "X-Api-Key: $RADARR_API_KEY" \
        "${RADARR_URL}/api/v3/${1}" 2>/dev/null
}

_radarr_lookup() {
    curl -sf --max-time 20 --get \
        --data-urlencode "term=$1" \
        -H "X-Api-Key: $RADARR_API_KEY" \
        "${RADARR_URL}/api/v3/movie/lookup" 2>/dev/null
}

_radarr_post() {
    curl -sf --max-time 20 -X POST \
        -H "X-Api-Key: $RADARR_API_KEY" \
        -H "Content-Type: application/json" \
        -d "$1" \
        "${RADARR_URL}/api/v3/movie" 2>/dev/null
}

_radarr_command() {
    curl -sf --max-time 20 -X POST \
        -H "X-Api-Key: $RADARR_API_KEY" \
        -H "Content-Type: application/json" \
        -d "$1" \
        "${RADARR_URL}/api/v3/command" 2>/dev/null
}

# Episode/garbage title filter — catches anime episodes stored as individual files
# in the Movies library, fansub release names, and codec metadata strings.
_is_episode_title() {
    local t="$1"
    [[ "$t" == *"_-_"* ]]                                          && return 0  # NANA_-_01_
    [[ "$t" == *".-."* ]]                                          && return 0  # Fractale.-.01
    [[ "$t" =~ ^\[.*\]\[.*\] ]]                                    && return 0  # [Title][NNN][...]
    [[ "$t" =~ [[:space:]]'-'[[:space:]][0-9]{2,3}$ ]]             && return 0  # Title - 001
    [[ "$t" =~ [[:space:]]E[0-9]{2,3}([[:space:]]|\[) ]]          && return 0  # Title E01 [group]
    [[ "${t^^}" == *"HEVC"* ]]                                     && return 0  # codec metadata
    [[ "$t" == *"(TMDB:"* ]]                                       && return 0  # codec metadata
    [[ "$t" == *$'\xef\xbf\xbd'* || "$t" == *"?"* ]]              && return 0  # encoding corruption
    return 1
}

# ==============================================================================================
# ━━━ Fetch Emby Movie Library ━━━
# ==============================================================================================
echo ""
echo "━━━━━ $ICON_SUMMARY Emby → Radarr Sync — $(date '+%Y-%m-%d %H:%M:%S') ━━━━━"
echo "$ICON_HOST $MY_ID ($LOCAL_SERVER_NAME)"
[[ "$DRY_RUN" == true ]] && warn "DRY RUN — no movies will be added"

echo ""
echo "━━━ $ICON_SYNC Emby Movie Library ━━━"

declare -A EMBY_MOVIES  # name → tmdb_id (empty string if none)

if [[ "${#RADARR_EMBY_LIBRARIES[@]}" -gt 0 ]]; then
    LIBRARIES_JSON=$(emby_api "Library/VirtualFolders") || { error "Could not fetch Emby libraries"; exit 1; }
    for lib_name in "${RADARR_EMBY_LIBRARIES[@]}"; do
        lib_id=$(echo "$LIBRARIES_JSON" | jq -r --arg n "$lib_name" '.[] | select(.Name == $n) | .ItemId' 2>/dev/null)
        if [[ -z "$lib_id" ]]; then
            warn "Emby library not found: $lib_name"
            continue
        fi
        log "Scanning library: $lib_name (ItemId: $lib_id)"
        LIB_JSON=$(emby_api "Items?ParentId=${lib_id}&IncludeItemTypes=Movie&Recursive=true&Fields=ProviderIds&Limit=5000") || {
            warn "Could not fetch movies from library: $lib_name"
            continue
        }
        while IFS='|' read -r name tmdb_id; do
            [[ -z "$name" || "$name" == "null" ]] && continue
            _is_episode_title "$name" && { log "  $ICON_SKIP Skipping episode/garbage: $name"; continue; }
            EMBY_MOVIES["$name"]="$tmdb_id"
        done < <(echo "$LIB_JSON" | jq -r '.Items[] | [.Name, (.ProviderIds.Tmdb // "")] | join("|")' 2>/dev/null)
    done
else
    log "RADARR_EMBY_LIBRARIES empty — scanning all Emby libraries"
    EMBY_MOVIES_JSON=$(emby_api "Items?IncludeItemTypes=Movie&Recursive=true&Fields=ProviderIds&Limit=10000") || {
        error "Could not fetch Emby movies"
        exit 1
    }
    while IFS='|' read -r name tmdb_id; do
        [[ -z "$name" || "$name" == "null" ]] && continue
        _is_episode_title "$name" && { log "  $ICON_SKIP Skipping episode/garbage: $name"; continue; }
        EMBY_MOVIES["$name"]="$tmdb_id"
    done < <(echo "$EMBY_MOVIES_JSON" | jq -r '.Items[] | [.Name, (.ProviderIds.Tmdb // "")] | join("|")' 2>/dev/null)
fi

EMBY_COUNT=${#EMBY_MOVIES[@]}
log "$EMBY_COUNT movies in Emby library"

if [[ "$EMBY_COUNT" -eq 0 ]]; then
    warn "No movies found in Emby library"
    exit 0
fi

# ==============================================================================================
# ━━━ Fetch Radarr Library ━━━
# ==============================================================================================
echo ""
echo "━━━ $ICON_SYNC Radarr Library ━━━"

# Cache-first — arr_get_tracked_data() serves the shared cache when it's fresh (kept current
# every 30min by arr_cache_prefill.sh in CRITICAL_MAINTENANCE_SCRIPTS), falls back to a live
# fetch when it's stale, and waits out an active rescan before either.
RADARR_MOVIES_JSON=$(arr_get_tracked_data "radarr" "$RADARR_URL" "$RADARR_API_KEY" "v3") || { error "Could not fetch Radarr movies"; exit 1; }

declare -A RADARR_TMDB    # tmdb_id → 1
declare -A RADARR_TITLES  # lower(title) → 1

while IFS='|' read -r title tmdb_id; do
    [[ -n "$title" ]] && RADARR_TITLES["${title,,}"]=1
    [[ -n "$tmdb_id" && "$tmdb_id" != "0" ]] && RADARR_TMDB["$tmdb_id"]=1
done < <(echo "$RADARR_MOVIES_JSON" | jq -r '.[] | [.title, (.tmdbId // 0 | tostring)] | join("|")' 2>/dev/null)

RADARR_COUNT=${#RADARR_TITLES[@]}
log "$RADARR_COUNT movies already in Radarr"

# ==============================================================================================
# ━━━ Find Gaps ━━━
# ==============================================================================================
echo ""
echo "━━━ $ICON_GEAR Comparing Libraries ━━━"

declare -A MISSING  # name → tmdb_id
ALREADY=0

for name in "${!EMBY_MOVIES[@]}"; do
    tmdb_id="${EMBY_MOVIES[$name]}"

    if [[ -n "$tmdb_id" && "${RADARR_TMDB[$tmdb_id]+x}" ]]; then
        (( ALREADY++ ))
        log "  $ICON_SKIP Already tracked (TMDB $tmdb_id): $name"
        continue
    fi

    if [[ "${RADARR_TITLES[${name,,}]+x}" ]]; then
        (( ALREADY++ ))
        log "  $ICON_SKIP Already tracked (title): $name"
        continue
    fi

    MISSING["$name"]="$tmdb_id"
    log "  $ICON_WARN Not in Radarr: $name${tmdb_id:+ (TMDB: $tmdb_id)}"
done

IFS=$'\n' SORTED_MISSING=($(printf '%s\n' "${!MISSING[@]}" | sort))

echo "  Already tracked: $ALREADY | Missing from Radarr: ${#MISSING[@]}"

if [[ "${#MISSING[@]}" -eq 0 ]]; then
    echo "Radarr already tracks everything in Emby"
    exit 0
fi

echo ""
echo "━━━ $ICON_SUMMARY Movies to add (${#MISSING[@]}) ━━━"
for name in "${SORTED_MISSING[@]}"; do
    _tmdb="${MISSING[$name]}"
    log "  $name${_tmdb:+ (TMDB: $_tmdb)}"
done

if [[ "$DRY_RUN" == true ]]; then
    warn "DRY RUN complete — run without --dry-run to add these movies"
    exit 0
fi

# ==============================================================================================
# ━━━ Add to Radarr ━━━
# ==============================================================================================
echo ""
echo "━━━ $ICON_SYNC Adding to Radarr ━━━"

RADARR_ROOT=$(_radarr_get "rootfolder" | jq -r 'first(.[] | select(.accessible == true)) | .path' 2>/dev/null)
QUALITY_ID=$(_radarr_get "qualityprofile" | jq -r '.[0].id' 2>/dev/null)

if [[ -z "$RADARR_ROOT" ]]; then
    error "Could not determine Radarr root folder"
    exit 1
fi
log "Root folder: $RADARR_ROOT | Quality profile: $QUALITY_ID"

ADDED=0
FAILED=0

for name in "${SORTED_MISSING[@]}"; do
    tmdb_id="${MISSING[$name]}"

    if [[ -n "$tmdb_id" ]]; then
        LOOKUP=$(_radarr_lookup "tmdb:$tmdb_id")
    else
        LOOKUP=$(_radarr_lookup "$name")
    fi

    if [[ -z "$LOOKUP" ]] || echo "$LOOKUP" | jq -e '. == [] or . == null' >/dev/null 2>&1; then
        warn "  $ICON_WARN No match in Radarr lookup: $name"
        (( FAILED++ ))
        continue
    fi

    MOVIE_DATA=$(echo "$LOOKUP" | jq '.[0]' 2>/dev/null)
    RADARR_TITLE=$(echo "$MOVIE_DATA" | jq -r '.title // ""' 2>/dev/null)

    if [[ -z "$RADARR_TITLE" ]]; then
        warn "  $ICON_WARN Empty result for: $name"
        (( FAILED++ ))
        continue
    fi

    PAYLOAD=$(echo "$MOVIE_DATA" | jq \
        --arg root "$RADARR_ROOT" \
        --argjson qid "$QUALITY_ID" \
        '. + {
            rootFolderPath: $root,
            qualityProfileId: $qid,
            monitored: true,
            addOptions: {
                searchForMovie: false
            }
        }' 2>/dev/null)

    RESULT=$(_radarr_post "$PAYLOAD")

    if echo "$RESULT" | jq -e '.id' >/dev/null 2>&1; then
        MOVIE_ID=$(echo "$RESULT" | jq -r '.id')
        _radarr_command "{\"name\":\"MoviesSearch\",\"movieIds\":[${MOVIE_ID}]}" >/dev/null
        log "  $ICON_DONE Added: $RADARR_TITLE"
        (( ADDED++ ))
    else
        warn "  $ICON_WARN Failed to add: $name"
        log "  $(echo "$RESULT" | head -c 200)"
        (( FAILED++ ))
    fi
done

# ==============================================================================================
# ━━━ Summary ━━━
# ==============================================================================================
echo ""
echo "━━━━━ $ICON_SUMMARY SYNC COMPLETE ━━━━━"
echo "  $ICON_DONE  Added:   $ADDED"
[[ "$FAILED" -gt 0 ]] && echo "  $ICON_WARN  Failed:  $FAILED"
echo "  $ICON_SKIP  Already tracked: $ALREADY"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

[[ "$ADDED" -gt 0 ]] && notify \
    "$ADDED movie(s) added to Radarr from Emby library on $(hostname)" \
    "Emby → Radarr Sync" "normal"

exit 0
