#!/bin/sh

BASE="/mnt/onboard/.adds/kobo-sideload-sync"
BIN="$BASE/bin/kobo-receiver"
RUN_DIR="$BASE/run"
STAGING_ROOT="$BASE/staging"
LIBRARY_DIR="/mnt/onboard/Books/SendToKobo"
PID_FILE="$RUN_DIR/receiver.pid"
STATUS_FILE="$RUN_DIR/status.txt"
SESSION_FILE="$RUN_DIR/session.json"
LOG_FILE="$RUN_DIR/receiver.log"
START_WAIT_TENTHS="${KSS_START_WAIT_TENTHS:-350}"
KEEP_PENDING="${KSS_KEEP_PENDING:-0}"

if [ -r "$BASE/action-timing.sh" ]; then
    . "$BASE/action-timing.sh"
else
    kss_timing_event() { :; }
fi

kss_timing_event receiver_start_enter

if [ -r "$BASE/pairing-config.sh" ]; then
    . "$BASE/pairing-config.sh"
    kss_load_pairing_endpoint || kss_timing_event control_config_invalid
fi

case "$START_WAIT_TENTHS" in
    ''|*[!0-9]*) START_WAIT_TENTHS=350 ;;
esac

pid_is_ours() {
    candidate="$1"
    case "$candidate" in
        ''|*[!0-9]*) return 1 ;;
    esac
    kill -0 "$candidate" 2>/dev/null || return 1
    actual="$(readlink "/proc/$candidate/exe" 2>/dev/null)"
    [ "$actual" = "$BIN" ] || [ "$actual" = "$BIN (deleted)" ]
}

mkdir -p "$RUN_DIR" "$STAGING_ROOT" "$LIBRARY_DIR" || {
    kss_timing_event receiver_fail
    echo "无法创建 Receiver 目录。"
    exit 1
}

new_pid=""
if [ -e "$PID_FILE" ] || [ -L "$PID_FILE" ]; then
    # Do not read a FIFO/device, follow a link, or discard an empty/unreadable
    # record as if it were proof that the previous Receiver has stopped.
    if [ -L "$PID_FILE" ] || [ ! -f "$PID_FILE" ] || [ ! -r "$PID_FILE" ] || [ ! -s "$PID_FILE" ]; then
        kss_timing_event receiver_fail
        echo "PID 文件格式无效或无法安全读取（为空、非普通文件或不可读），已拒绝启动。请保留状态文件，通过 USB 检查。"
        exit 1
    fi
    old_pid="$(sed -n '1p' "$PID_FILE" 2>/dev/null)" || old_pid=""
    case "$old_pid" in
        ''|*[!0-9]*)
            kss_timing_event receiver_fail
            echo "PID 文件格式无效，无法安全识别已有接收器进程；已拒绝启动。请保留状态文件，通过 USB 检查，不要重复开启无线传输。"
            exit 1
            ;;
    esac
    if pid_is_ours "$old_pid"; then
        if [ -s "$STATUS_FILE" ]; then
            kss_timing_event receiver_already_ready
            echo "无线传书已经开启。"
            sed -n 's/^LOCAL_PAGE_URL=/手机或电脑打开：/p' "$STATUS_FILE"
            exit 0
        fi
        # A previous quick launch may still be inside the Receiver's bounded
        # network wait. Reuse that exact process rather than starting a second
        # listener or discarding its eventual session.
        new_pid="$old_pid"
        kss_timing_event receiver_reused_waiting
    fi
    if [ -z "$new_pid" ] && kill -0 "$old_pid" 2>/dev/null; then
        kss_timing_event receiver_fail
        echo "无法确认 PID 对应的进程属于本项目，已拒绝启动。请保留状态文件，通过 USB 检查。"
        exit 1
    fi
    [ -n "$new_pid" ] || rm -f "$PID_FILE"
fi

if [ -z "$new_pid" ] && [ -f "$LOG_FILE" ]; then
    log_size="$(wc -c < "$LOG_FILE" 2>/dev/null)"
    case "$log_size" in
        ''|*[!0-9]*) log_size=0 ;;
    esac
    if [ "$log_size" -gt 262144 ]; then
        mv -f "$LOG_FILE" "$RUN_DIR/receiver.previous.log"
    fi
fi

if [ -z "$new_pid" ]; then
    # Also covers a direct launcher invocation outside the NickelMenu lease
    # path. Recovery checks recorded process liveness before changing code.
    if ! /bin/sh "$BASE/session-lease.sh" recover-update; then
        echo "接收器更新恢复尚未完成，请保留记录并通过 USB 检查。"
        exit 1
    fi
    if [ ! -f "$BIN" ]; then
        kss_timing_event receiver_fail
        echo "Receiver 程序不存在，请重新安装。"
        exit 1
    fi
    rm -f "$STATUS_FILE" "$SESSION_FILE" "$RUN_DIR/pairing.png"
    kss_timing_event receiver_spawn_begin
    "$BIN" \
    --self-update-bootstrap=receiver-binary/v1 \
    --listen="0.0.0.0:8181" \
	--upload-dir="$STAGING_ROOT" \
	--library-dir="$LIBRARY_DIR" \
	--session-file="$SESSION_FILE" \
	--status-file="$STATUS_FILE" \
	--pairing-image-file="$RUN_DIR/pairing.png" \
	--device-identity-file="$BASE/device-identity.json" \
	--device-id-file="$BASE/device-id" \
	--pairing-endpoint="${KSS_PAIRING_ENDPOINT:-}" \
	--keep-receiving="${KSS_KEEP_RECEIVING:-false}" \
	--pairing-sequence-file="$BASE/pairing-sequence.json" \
    --max-bytes=524288000 \
	--min-free-bytes=67108864 \
	--network-wait=30s \
	--ttl=1h \
        >>"$LOG_FILE" 2>&1 &
    new_pid=$!
    kss_timing_event receiver_spawn_end

    pid_tmp="$PID_FILE.tmp.$$"
    if ! printf '%s\n' "$new_pid" > "$pid_tmp" || ! mv -f "$pid_tmp" "$PID_FILE"; then
        kill "$new_pid" 2>/dev/null
        rm -f "$pid_tmp"
        kss_timing_event receiver_fail
        echo "无法记录 Receiver 进程。"
        exit 1
    fi
fi

attempt=0
kss_timing_event receiver_wait_begin
# The Receiver may spend up to 30 seconds waiting for Nickel's asynchronous
# Wi-Fi autoconnect action to obtain a LAN address. Keep this wrapper alive a
# little longer so it can surface the Receiver's specific result instead of
# killing a healthy startup after the old five-second window.
while [ "$attempt" -lt "$START_WAIT_TENTHS" ]; do
    if [ -s "$STATUS_FILE" ] && pid_is_ours "$new_pid"; then
        kss_timing_event receiver_ready
        echo "无线传书已开启；连续 1 小时没有操作后自动关闭，传输中不会关闭。"
        sed -n 's/^LOCAL_PAGE_URL=/手机或电脑打开：/p' "$STATUS_FILE"
        exit 0
    fi
    if ! kill -0 "$new_pid" 2>/dev/null; then
        break
    fi
    attempt=$((attempt + 1))
    sleep 0.1
done

if pid_is_ours "$new_pid" && [ "$KEEP_PENDING" = "1" ]; then
    kss_timing_event receiver_pending
    echo "无线传书正在等待 Wi-Fi 取得局域网地址，后台最多继续等待 30 秒。"
    exit 2
fi

if pid_is_ours "$new_pid"; then
    kill "$new_pid" 2>/dev/null
fi
rm -f "$PID_FILE" "$STATUS_FILE" "$SESSION_FILE" "$RUN_DIR/pairing.png"
kss_timing_event receiver_fail
last_log_line="$(tail -n 1 "$LOG_FILE" 2>/dev/null)"
case "$last_log_line" in
    *"no usable LAN IPv4 address found"*)
        echo "无线传书未开启：已请求连接 Wi-Fi，但30秒内没有取得局域网地址。"
        ;;
    *)
        echo "Receiver 启动失败。请查看：$LOG_FILE"
        ;;
esac
exit 1
