#!/bin/bash
# ==============================================================================================
# ============================= Trailer Folder Migration =======================================
# ==============================================================================================
#
# PURPOSE
# ─────────────────────────────────────────────────────────────────────────────
# One-off migration for TV show trailers downloaded before Trailarr's "Series
# Trailers" profile was corrected. Emby ingests TV trailers sitting at the
# series root using the movie-style "<Show> (Year)-trailer.ext" convention as
# fake episodes instead of recognizing them as trailers — confirmed via Emby's
# server log. The fix is a "trailers/" subfolder (lowercase) under the series
# folder containing a plain "trailer.ext" file — same convention Trailarr now
# uses going forward (customfilter_id=2, "Series Trailers" profile).
#
# This script only moves/renames existing misplaced files. It does not touch
# Trailarr or Emby — a normal periodic Emby library scan picks up the moved
# files on its own.
#
# ==============================================================================================
# OPERATIONAL MODEL
# ==============================================================================================
#
# Discovery
#   Scans SONARR_TV_ROOT one level deep for "*-trailer.*" files sitting
#   directly in a series folder (the movie-style convention).
#
# Single Trailer Per Show
#   <Show>/<Show> (Year)-trailer.mkv → <Show>/trailers/trailer.mkv
#
# Multiple Trailers Per Show
#   Sorted alphabetically for determinism. First file becomes trailer.ext,
#   subsequent files become trailer-2.ext, trailer-3.ext, etc. Emby's TV
#   trailer convention only requires the file to live in trailers/ — exact
#   filename beyond the first doesn't matter, but distinct names avoid
#   collisions and keep behavior deterministic on re-run.
#
# Collision Safety
#   If the destination filename already exists, the file is skipped and
#   logged as a conflict rather than overwritten. Lets the script be re-run
#   safely after a partial run or a manually resolved conflict.
#
# ==============================================================================================
# DESIGN PRINCIPLES
# ==============================================================================================
#
# Move, Never Copy or Delete
#   Files are relocated with mv and nothing is ever removed. A misjudged move is
#   reversible by hand; a delete is not. The script has no cleanup pass by design.
#
# Idempotent by Collision Skip
#   Re-running is safe because an existing destination is skipped rather than
#   overwritten. A partial run, an interrupted run, or a manually resolved conflict
#   can all be followed by a plain re-run.
#
# Deterministic Ordering
#   Multiple trailers per show are sorted before numbering, so the same input always
#   produces the same trailer.ext / trailer-2.ext assignment. Without the sort, the
#   numbering would depend on filesystem iteration order and a re-run could rename
#   files differently.
#
# Filesystem Only
#   Neither Trailarr nor Emby is touched. Emby's periodic library scan picks the moved
#   files up on its own — poking either service would add failure modes to what is
#   otherwise a pure file move.
#
# ==============================================================================================
# OPERATIONAL SAFEGUARDS
# ==============================================================================================
#
# Root Enforcement
#   Moves files owned by container users and chowns the created trailers/ directory.
#
# Lock Acquisition
#   acquire_lock prevents two runs numbering the same show's trailers concurrently.
#
# Host Detection
#   detect_hosts() aliases HOST*_SONARR_TV_ROOT → SONARR_TV_ROOT.
#
# TV Root Validation
#   Exits if SONARR_TV_ROOT is unset or is not a directory — the scan below is rooted
#   there, and an empty value would walk from the current directory.
#
# Bounded Scan Depth
#   find runs with -mindepth 2 -maxdepth 2, so only files sitting directly in a series
#   folder are considered. Trailers already correctly placed inside trailers/ are out
#   of range and cannot be picked up and re-moved.
#
# Collision Skip
#   An existing destination is never overwritten — the source is left in place and
#   counted as a conflict for review.
#
# Permission Matching on Created Directories
#   mkdir as root would leave trailers/ as root-owned. It is chowned to
#   PERMISSIONS_OWNER and chmodded to PERMISSIONS_DIR_MODE so it matches the rest of
#   the library and does not become an exception the permissions job has to correct.
#
# Dry Run Support
#   --dry-run reports every move and touches nothing.
#
# ==============================================================================================
# CONFIGURATION
# ==============================================================================================
#
# host*.conf
#
#   HOST*_SONARR_TV_ROOT
#       Host filesystem path to the TV library. Aliased by detect_hosts() →
#       SONARR_TV_ROOT.
#
# master.conf
#
#   PERMISSIONS_OWNER / PERMISSIONS_DIR_MODE
#       Applied to each created trailers/ directory so it matches library convention.
#       Shared with media_shares_permissions.sh. (defaults: nobody:users, 755)
#
# ==============================================================================================
# RUNTIME MODES
# ==============================================================================================
#
# trailer_folder_migration.sh
#     Move every misplaced trailer file into <show>/trailers/.
#
# trailer_folder_migration.sh --dry-run
#     Show what would move, with no filesystem changes.
#
# trailer_folder_migration.sh --log
#     Verbose output — per-file source/destination.
#
# ==============================================================================================

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

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

parse_args "$@"

# ==============================================================================================
# ━━━ Setup ━━━
# ==============================================================================================
# Moves container-owned media files and chowns the trailers/ dirs it creates.
if [[ "$EUID" -ne 0 ]]; then
    error "Must be run as root"
    exit 1
fi

acquire_lock

# detect_hosts() sets MY_ID and aliases HOST*_SONARR_TV_ROOT → SONARR_TV_ROOT
detect_hosts

if [[ -z "${SONARR_TV_ROOT:-}" ]]; then
    error "SONARR_TV_ROOT not set for $MY_ID — check HOST*_SONARR_TV_ROOT in host*.conf"
    exit 1
fi

if [[ ! -d "$SONARR_TV_ROOT" ]]; then
    error "SONARR_TV_ROOT not found: $SONARR_TV_ROOT"
    exit 1
fi

log "Identity: $MY_ID ($LOCAL_SERVER_NAME)"
log "TV root:  $SONARR_TV_ROOT"
[[ "$DRY_RUN" == true ]] && warn "DRY RUN — no files will be moved"

# ==============================================================================================
# ━━━ Discover misplaced trailer files, grouped by show ━━━
# ==============================================================================================
echo ""
echo "━━━ $ICON_CLEAN Trailer Folder Migration — $MY_ID ━━━"

START=$(date +%s)

declare -A SHOW_FILES=()   # show dir → newline-separated list of trailer file paths
while IFS= read -r -d '' f; do
    show_dir="$(dirname "$f")"
    SHOW_FILES["$show_dir"]+="$f"$'\n'
done < <(find "$SONARR_TV_ROOT" -mindepth 2 -maxdepth 2 -iname "*-trailer.*" -print0)

TOTAL_SHOWS=${#SHOW_FILES[@]}
if [[ "$TOTAL_SHOWS" -eq 0 ]]; then
    echo "$ICON_DONE No misplaced trailer files found — nothing to migrate"
    exit 0
fi

warn "$TOTAL_SHOWS show(s) with misplaced trailer file(s)"

MOVED=0
SKIPPED=0
FAILED=0
FAIL_LIST=()

for show_dir in "${!SHOW_FILES[@]}"; do
    mapfile -t files < <(printf '%s' "${SHOW_FILES[$show_dir]}" | sort)
    trailers_dir="$show_dir/trailers"
    show_name="$(basename "$show_dir")"

    if [[ "$DRY_RUN" != true ]]; then
        mkdir -p "$trailers_dir" || {
            error "$show_name — could not create trailers/ dir"
            FAILED=$(( FAILED + ${#files[@]} ))
            FAIL_LIST+=("$show_name")
            continue
        }
        # mkdir as root defaults to root:root 777 — match the library's
        # nobody:users / 755 convention (PERMISSIONS_OWNER/PERMISSIONS_DIR_MODE)
        chown "${PERMISSIONS_OWNER:-nobody:users}" "$trailers_dir" 2>/dev/null
        chmod "${PERMISSIONS_DIR_MODE:-755}" "$trailers_dir" 2>/dev/null
    fi

    idx=0
    for src in "${files[@]}"; do
        [[ -z "$src" ]] && continue
        idx=$(( idx + 1 ))
        ext="${src##*.}"
        if [[ "$idx" -eq 1 ]]; then
            dest="$trailers_dir/trailer.$ext"
        else
            dest="$trailers_dir/trailer-$idx.$ext"
        fi

        if [[ "$DRY_RUN" == true ]]; then
            log "$show_name — would move: $(basename "$src") → trailers/$(basename "$dest")"
            MOVED=$(( MOVED + 1 ))
            continue
        fi

        if [[ -e "$dest" ]]; then
            warn "$show_name — $(basename "$dest") already exists, skipping $(basename "$src")"
            SKIPPED=$(( SKIPPED + 1 ))
            continue
        fi

        if mv "$src" "$dest"; then
            log "$show_name — $(basename "$src") → trailers/$(basename "$dest")"
            MOVED=$(( MOVED + 1 ))
        else
            error "$show_name — failed to move $(basename "$src")"
            FAILED=$(( FAILED + 1 ))
            FAIL_LIST+=("$show_name")
        fi
    done
done

END=$(date +%s)

# ==============================================================================================
# ━━━ Summary ━━━
# ==============================================================================================
echo ""
echo "━━━━━ $ICON_SUMMARY TRAILER MIGRATION SUMMARY ━━━━━"
echo "$ICON_HOST    Identity:  $MY_ID ($LOCAL_SERVER_NAME)"
echo "$ICON_CLEAN   Shows:     $TOTAL_SHOWS"
echo "$ICON_TIME    Duration:  $(format_duration $(( END - START )))"
echo ""
echo "$ICON_DONE    Moved:     $MOVED"
[[ "$SKIPPED" -gt 0 ]] && echo "$ICON_SKIP    Skipped:   $SKIPPED (destination already existed)"
[[ "$FAILED"  -gt 0 ]] && echo "$ICON_ERROR   Failed:    $FAILED"
echo ""

if [[ "$DRY_RUN" == true ]]; then
    warn "DRY RUN — no changes made"
elif [[ "$FAILED" -gt 0 ]]; then
    echo "$ICON_ERROR Status: SOME MOVES FAILED — ${FAIL_LIST[*]}"
    notify "Trailer folder migration failed for: ${FAIL_LIST[*]}" \
        "Trailer Migration" "warning"
else
    echo "$ICON_DONE Status: done — $MOVED file(s) migrated across $TOTAL_SHOWS show(s)"
fi
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

[[ "$FAILED" -gt 0 ]] && exit 1
exit 0
