#!/bin/bash
# ==============================================================================================
# ================================= Ramdisk Stop ===============================================
# ==============================================================================================
#
# PURPOSE
# ─────────────────────────────────────────────────────────────────────────────
# Safely stops the transcode ramdisk: redirects the transcode symlink to the
# SSD fallback before unmounting so Emby continues writing without interruption,
# then unmounts the tmpfs and updates the state file.
#
# Primary use case: stopping the current ramdisk before re-running
# ramdisk_setup.sh with new size or threshold values (setup is idempotent —
# if the ramdisk is mounted, it skips the mount and reports status, so you
# must stop it first to change the size).
#
# ==============================================================================================
# OPERATIONAL MODEL
# ==============================================================================================
#
# Executes in safe order:
#   1. Validate — ramdisk mounted, SSD fallback exists
#   2. Redirect symlink → SSD (Emby immediately writes to SSD instead)
#   3. Warn if active transcode files still on ramdisk (informational — not a blocker)
#   4. Unmount ramdisk tmpfs
#   5. Update /tmp/transcode_state.db → current_target=TRANSCODE_SSD
#
# The symlink redirect happens before unmount so there is no window where Emby
# has nowhere to write. Existing in-progress transcode files on the ramdisk are
# lost on unmount — warn the user but proceed (this is expected for maintenance).
#
# ==============================================================================================
# DESIGN PRINCIPLES
# ==============================================================================================
#
# Redirect Before Unmounting
#   The symlink is pointed at the SSD fallback first, and only then is the tmpfs
#   unmounted. Reversing that order would leave in-flight transcodes writing into a
#   path that is being pulled out from under them. New sessions land on SSD from the
#   moment of the flip; existing ones drain.
#
# Unmount Is the Data Loss
#   Everything on a tmpfs disappears when it is unmounted — there is nothing to migrate
#   and no way to preserve it. That is acceptable only because the contents are
#   regenerable transcode segments, which is exactly why this operation is safe for
#   transcodes and would not be for any other kind of ramdisk.
#
# Not Mounted Is Success
#   An already-unmounted ramdisk is reported and treated as done, not as an error. The
#   goal state is "ramdisk not mounted", and the script is idempotent toward it.
#
# State File Reflects Reality
#   The transcode state file is updated to record the SSD target, so transcode_manager.sh
#   agrees with what actually happened rather than trying to flip back to a ramdisk that
#   no longer exists.
#
# ==============================================================================================
# OPERATIONAL SAFEGUARDS
# ==============================================================================================
#
# Root Required
#   umount requires root.
#
# Single Instance Lock
#   acquire_lock prevents concurrent stop attempts.
#
# Mounted Check
#   Exits cleanly if ramdisk is not mounted — nothing to do.
#
# Symlink-First Order
#   Symlink is redirected before unmount — Emby never sees a broken path.
#
# transcode_manager Warning
#   Warns if transcode_manager.sh is running — it may flip the symlink back
#   to ramdisk on its next cycle. Stop transcode_manager before running this
#   if you need the SSD redirect to hold.
#
# ==============================================================================================
# CONFIGURATION
# ==============================================================================================
#
# host*.conf
#   HOST*_TRANSCODE_SSD     SSD fallback directory — redirect target during stop.
#                           Aliased by detect_hosts() → TRANSCODE_SSD.
#
# master.conf
#   TRANSCODE_LINK          Symlink Emby uses. Must match Emby's transcode path setting.
#   RAMDISK_PATH            tmpfs mount point.
#   TRANSCODE_STATE_FILE    Override state file path (default: ${STATE_DIR}/transcode_state.db).
#
# ==============================================================================================
# STATE FILES
# ==============================================================================================
#
#   /tmp/transcode_state.db    — updated to current_target=TRANSCODE_SSD after stop.
#                                transcode_manager.sh reads this on its next cycle.
#
# ==============================================================================================
# RUNTIME MODES
# ==============================================================================================
#
# ramdisk_stop.sh
#     Stop the ramdisk: redirect symlink → SSD, unmount, update state.
#
# ramdisk_stop.sh --dry-run
#     Show what would happen without making any changes.
#
# ramdisk_stop.sh --status
#     Show current mount state, symlink target, active files on ramdisk. Exit.
#
# ramdisk_stop.sh --log
#     Verbose output for each step.
#
# ==============================================================================================

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

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

parse_args "$@"

# ==============================================================================================
# ━━━ Setup ━━━
# ==============================================================================================
if [[ "$EUID" -ne 0 ]]; then
    error "Must be run as root — umount requires root"
    exit 1
fi


acquire_lock

detect_hosts

STATE_FILE="${TRANSCODE_STATE_FILE:-${STATE_DIR:-/tmp}/transcode_state.db}"

log "Identity:  $MY_ID ($LOCAL_SERVER_NAME)"
log "Ramdisk:   $RAMDISK_PATH"
log "Fallback:  $TRANSCODE_SSD"
log "Symlink:   $TRANSCODE_LINK"

[[ "$DRY_RUN" == true ]] && warn "DRY RUN — no changes will be made"

# ==============================================================================================
# ━━━ Status ━━━
# ==============================================================================================
if [[ "$SHOW_STATUS" == true ]]; then
    echo ""
    echo "━━━━━ $ICON_SUMMARY STATUS ━━━━━"
    echo "$ICON_HOST   Identity:     $MY_ID ($LOCAL_SERVER_NAME)"
    echo "$ICON_RAM    Ramdisk path: $RAMDISK_PATH"
    echo "$ICON_DISK   SSD fallback: $TRANSCODE_SSD"
    echo "$ICON_LINK   Symlink:      $TRANSCODE_LINK"
    echo ""

    if mountpoint -q "$RAMDISK_PATH" 2>/dev/null; then
        USAGE=$(df -BG "$RAMDISK_PATH" | awk 'NR==2 {print $3}')
        AVAIL=$(df -BG "$RAMDISK_PATH" | awk 'NR==2 {print $4}')
        echo "  $ICON_RAM  Ramdisk: mounted — $USAGE used / $AVAIL available ✅"
        FILE_COUNT=$(find "$RAMDISK_PATH" -type f 2>/dev/null | wc -l)
        echo "  $ICON_RAM  Active files on ramdisk: $FILE_COUNT"
    else
        echo "  $ICON_RAM  Ramdisk: NOT mounted"
    fi

    if [[ -L "$TRANSCODE_LINK" ]]; then
        TARGET=$(readlink "$TRANSCODE_LINK")
        echo "  $ICON_LINK Symlink: $TRANSCODE_LINK → $TARGET"
    else
        echo "  $ICON_LINK Symlink: not set"
    fi

    if [[ -f "$STATE_FILE" ]]; then
        echo ""
        echo "  State file ($STATE_FILE):"
        while IFS='=' read -r key value; do
            [[ -z "$key" ]] && continue
            echo "    $key = $value"
        done < "$STATE_FILE"
    else
        echo "  $ICON_INFO State file: not found (ramdisk never started this boot)"
    fi

    if pgrep -f "transcode_manager.sh" >/dev/null 2>&1; then
        echo ""
        warn "transcode_manager.sh is currently RUNNING"
    fi

    echo "━━━━━━━━━━━━━━━━━━━━━━━"
    exit 0
fi

# ==============================================================================================
# ━━━ Preflight ━━━
# ==============================================================================================
echo ""
echo "━━━ $ICON_GEAR Preflight ━━━"

# Bail if not mounted — nothing to do
if ! mountpoint -q "$RAMDISK_PATH" 2>/dev/null; then
    warn "Ramdisk is not mounted at $RAMDISK_PATH — nothing to stop"
    exit 0
fi

echo "Ramdisk is mounted ✅"

# Warn if transcode_manager is running — it may flip symlink back on next cycle
if pgrep -f "transcode_manager.sh" >/dev/null 2>&1; then
    warn "transcode_manager.sh is currently RUNNING"
    warn "It may flip the symlink back to ramdisk on its next cycle"
    warn "Stop transcode_manager.sh first if you need the SSD redirect to hold"
    echo ""
fi

# Confirm SSD fallback exists
if [[ ! -d "$TRANSCODE_SSD" ]]; then
    if [[ "$DRY_RUN" == true ]]; then
        warn "DRY RUN — SSD fallback does not exist: $TRANSCODE_SSD"
        warn "DRY RUN — would create it before redirecting symlink"
    else
        warn "SSD fallback does not exist — creating: $TRANSCODE_SSD"
        mkdir -p "$TRANSCODE_SSD" || {
            error "Failed to create SSD fallback: $TRANSCODE_SSD"
            error "Cannot safely redirect symlink — aborting"
            exit 1
        }
        echo "SSD fallback created ✅"
    fi
else
    echo "SSD fallback exists: $TRANSCODE_SSD ✅"
fi

START=$(date +%s)
STOP_SUCCESS=true

# ==============================================================================================
# ━━━ Redirect Symlink → SSD ━━━
# ==============================================================================================
# Redirect BEFORE unmount — Emby continues writing to SSD with no broken path window.
echo ""
echo "━━━ $ICON_LINK Redirect Symlink → SSD ━━━"

if [[ -L "$TRANSCODE_LINK" ]]; then
    CURRENT_TARGET=$(readlink "$TRANSCODE_LINK")
    if [[ "$CURRENT_TARGET" == "$TRANSCODE_SSD" ]]; then
        echo "Symlink already points to SSD — no change needed ✅"
    else
        if [[ "$DRY_RUN" == true ]]; then
            warn "DRY RUN — would redirect: $TRANSCODE_LINK → $TRANSCODE_SSD"
        else
            ln -sfn "$TRANSCODE_SSD" "$TRANSCODE_LINK" && \
                warn "Symlink redirected: $TRANSCODE_LINK → $TRANSCODE_SSD ✅" || {
                error "Failed to redirect symlink"
                STOP_SUCCESS=false
            }
        fi
    fi
elif [[ -e "$TRANSCODE_LINK" ]]; then
    warn "$TRANSCODE_LINK exists but is not a symlink — leaving as-is"
else
    warn "Symlink $TRANSCODE_LINK does not exist — nothing to redirect"
fi

# ==============================================================================================
# ━━━ Active Files Warning ━━━
# ==============================================================================================
echo ""
echo "━━━ $ICON_RAM Active Files Check ━━━"

FILE_COUNT=$(find "$RAMDISK_PATH" -type f 2>/dev/null | wc -l)
if [[ "$FILE_COUNT" -gt 0 ]]; then
    warn "⚠️  $FILE_COUNT file(s) still on ramdisk — will be lost on unmount"
    warn "Active transcode sessions should be stopped before unmounting"
    warn "Proceeding regardless (this is expected for maintenance)"
    if [[ "$ENABLE_LOGGING" == true ]]; then
        find "$RAMDISK_PATH" -type f 2>/dev/null | while read -r f; do
            log "  $f"
        done
    fi
else
    echo "No active files on ramdisk ✅"
fi

# ==============================================================================================
# ━━━ Unmount ━━━
# ==============================================================================================
echo ""
echo "━━━ $ICON_RAM Unmount Ramdisk ━━━"

if [[ "$DRY_RUN" == true ]]; then
    warn "DRY RUN — would unmount: $RAMDISK_PATH"
else
    if umount "$RAMDISK_PATH" 2>/dev/null; then
        warn "Ramdisk unmounted: $RAMDISK_PATH ✅"
    else
        # Regular unmount failed — check if only directory handles are open (no active writes)
        OPEN_FILES=$(lsof +D "$RAMDISK_PATH" 2>/dev/null | awk 'NR>1 && $5 != "DIR"' | wc -l)
        if [[ "$OPEN_FILES" -eq 0 ]]; then
            warn "Busy — only directory handles open, no active writes — trying lazy unmount"
            if umount -l "$RAMDISK_PATH"; then
                warn "Ramdisk lazy-unmounted: $RAMDISK_PATH ✅"
                warn "Handles will release when owning processes next check the directory"
            else
                error "Lazy unmount also failed — $RAMDISK_PATH"
                STOP_SUCCESS=false
            fi
        else
            error "Failed to unmount $RAMDISK_PATH — $OPEN_FILES file(s) still open for writing"
            error "Stop active transcode sessions and retry"
            STOP_SUCCESS=false
        fi
    fi
fi

# ==============================================================================================
# ━━━ Update State File ━━━
# ==============================================================================================
echo ""
echo "━━━ $ICON_GEAR State File ━━━"

if [[ "$DRY_RUN" == true ]]; then
    warn "DRY RUN — would update $STATE_FILE: current_target=$TRANSCODE_SSD"
elif [[ "$STOP_SUCCESS" == true ]]; then
    NOW=$(date +%s)
    cat > "$STATE_FILE" <<EOF
current_target=$TRANSCODE_SSD
last_flip_time=$NOW
flip_count_hour=0
flip_hour_start=$NOW
EOF
    echo "State file updated: current_target=$TRANSCODE_SSD"
else
    warn "Skipping state file update — stop had errors"
fi

END=$(date +%s)

# ==============================================================================================
# ━━━ Summary ━━━
# ==============================================================================================
echo ""
echo "━━━━━ $ICON_SUMMARY RAMDISK STOP SUMMARY ━━━━━"
echo "$ICON_HOST  Identity: $MY_ID ($LOCAL_SERVER_NAME)"
echo "$ICON_RAM   Ramdisk:  $RAMDISK_PATH"
echo "$ICON_DISK  Fallback: $TRANSCODE_SSD"
echo "$ICON_LINK  Symlink:  $TRANSCODE_LINK → $(readlink "$TRANSCODE_LINK" 2>/dev/null || echo "not set")"
echo "$ICON_TIME  Duration: $(format_duration $(( END - START )))"
echo ""

if [[ "$DRY_RUN" == true ]]; then
    warn "DRY RUN — no changes made"
elif [[ "$STOP_SUCCESS" == true ]]; then
    echo "$ICON_DONE Status: done ✅"
    echo "Run ramdisk_setup.sh to remount with new configuration"
else
    echo "$ICON_ERROR Status: STOP HAD ERRORS"
    notify "Ramdisk stop errors on $(hostname) ($MY_ID) — check output" \
        "Ramdisk Stop" "warning"
    exit 1
fi
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
