#!/usr/bin/env bash
# =============================================================================
# onx-trash-restore — Move a trashed item back to its original path
#
# Purpose:
#   Reads ~/.trash/<trash_id>/.meta.json, recreates the parent directory of
#   the original path, and moves the item back. The trash entry directory is
#   removed afterwards. When the original path is already occupied the caller
#   may supply `overwrite=true` or `dest_override` to land it elsewhere.
#
# Input (stdin JSON):
#   {
#     "username":      "onx_xxxx",
#     "trash_id":      "5f3a1b6e",
#     "overwrite":     false,             -- optional; default false
#     "dest_override": null               -- optional; rel path to land instead
#   }
#
# Output (stdout JSON):
#   {
#     "trash_id":     "5f3a1b6e",
#     "restored_to":  "/home/onx_xxxx/public_html/old-stuff/draft.html",
#     "original_path": "public_html/old-stuff/draft.html",
#     "size_bytes":   1247,
#     "overwritten":  false
#   }
#
# Exit codes: 0=ok 1=invalid-input 2=preflight-fail 3=execution-fail
# Deployed to: /usr/local/onoxsoft/bin/onx-trash-restore
# =============================================================================

set -euo pipefail

SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
# shellcheck source=_lib/common.sh
source "${SCRIPT_DIR}/_lib/common.sh"

require_cmd jq
require_cmd mv

onx_json_input

USERNAME="$(onx_json_field username)"
TRASH_ID="$(onx_json_field trash_id)"
OVERWRITE="$(onx_json_get_bool "$INPUT" overwrite false)"
DEST_OVERRIDE="$(onx_json_field dest_override "")"

onx_validate_username "$USERNAME"
[[ -z "${TRASH_ID}" ]] && onx_die 1 "trash_id is required"
# trash_id must be safe (alnum/hex only).
[[ "${TRASH_ID}" =~ ^[a-zA-Z0-9_-]+$ ]] || onx_die 1 "invalid trash_id"

HOME_DIR="/home/${USERNAME}"
[[ -d "$HOME_DIR" ]] || onx_die 2 "home directory missing: ${HOME_DIR}"

TRASH_ROOT="${HOME_DIR}/.trash"
TRASH_ENTRY="${TRASH_ROOT}/${TRASH_ID}"
META="${TRASH_ENTRY}/.meta.json"

[[ -d "${TRASH_ENTRY}" ]] || onx_die 2 "trash entry not found: ${TRASH_ID}"
[[ -f "${META}" ]]        || onx_die 2 "trash meta missing: ${TRASH_ID}"

ORIG_PATH="$(jq -r '.original_path // ""' "${META}" 2>/dev/null)"
ORIG_BN="$(jq -r '.original_basename // ""' "${META}" 2>/dev/null)"
SIZE="$(jq -r '.size_bytes // 0' "${META}" 2>/dev/null)"

[[ -z "${ORIG_PATH}" || -z "${ORIG_BN}" ]] && onx_die 2 "trash meta corrupt: ${TRASH_ID}"

# Find the actual payload inside the trash entry (exclude .meta.json).
PAYLOAD=""
shopt -s nullglob dotglob
for f in "${TRASH_ENTRY}"/*; do
    [[ "$(basename "${f}")" == ".meta.json" ]] && continue
    PAYLOAD="${f}"
    break
done
shopt -u nullglob dotglob

[[ -z "${PAYLOAD}" ]] && onx_die 2 "trash entry empty: ${TRASH_ID}"

# Decide destination: override or original path.
if [[ -n "${DEST_OVERRIDE}" ]]; then
    DEST_INPUT="${HOME_DIR}/${DEST_OVERRIDE#/}"
else
    DEST_INPUT="${HOME_DIR}/${ORIG_PATH#/}"
fi
DEST_ABS="$(realpath -m "${DEST_INPUT}" 2>/dev/null || printf '%s' "${DEST_INPUT}")"

# Path-traversal guard.
case "${DEST_ABS}" in
    "${HOME_DIR}"|"${HOME_DIR}"/*) ;;
    *) onx_die 1 "destination escapes /home/${USERNAME}: ${DEST_ABS}" ;;
esac

# Prevent restoring back into the trash.
case "${DEST_ABS}" in
    "${TRASH_ROOT}"|"${TRASH_ROOT}"/*) onx_die 1 "cannot restore into trash" ;;
esac

# Ensure parent dir exists.
DEST_PARENT="$(dirname "${DEST_ABS}")"
[[ -d "${DEST_PARENT}" ]] || mkdir -p "${DEST_PARENT}"

OVERWRITTEN="false"
if [[ -e "${DEST_ABS}" ]]; then
    if [[ "${OVERWRITE}" != "true" ]]; then
        onx_die 2 "destination exists (use overwrite=true): ${ORIG_PATH}"
    fi
    rm -rf -- "${DEST_ABS}" 2>/dev/null \
        || onx_die 3 "failed to remove existing destination"
    OVERWRITTEN="true"
fi

# Atomic move when on same device, otherwise cp+rm.
SRC_DEV="$(stat -c '%d' "${PAYLOAD}" 2>/dev/null || echo 0)"
DST_DEV="$(stat -c '%d' "${DEST_PARENT}" 2>/dev/null || echo 0)"

if [[ "${SRC_DEV}" == "${DST_DEV}" ]]; then
    mv -f -- "${PAYLOAD}" "${DEST_ABS}" 2>/dev/null \
        || onx_die 3 "restore mv failed"
else
    cp -a -- "${PAYLOAD}" "${DEST_ABS}" 2>/dev/null \
        || onx_die 3 "cross-device restore failed"
    rm -rf -- "${PAYLOAD}" 2>/dev/null || true
fi

# Wipe the trash entry directory (now empty except for .meta.json).
rm -rf -- "${TRASH_ENTRY}" 2>/dev/null || true

onx_log "trash-restore: user=${USERNAME} trash_id=${TRASH_ID} to='${ORIG_PATH}' overwritten=${OVERWRITTEN}"

jq -nc \
    --arg trash_id "${TRASH_ID}" \
    --arg restored_to "${DEST_ABS}" \
    --arg original_path "${ORIG_PATH}" \
    --argjson size_bytes "${SIZE:-0}" \
    --argjson overwritten "$([[ "${OVERWRITTEN}" == "true" ]] && echo true || echo false)" \
    '{
        trash_id: $trash_id,
        restored_to: $restored_to,
        original_path: $original_path,
        size_bytes: $size_bytes,
        overwritten: $overwritten
     }'
