#!/bin/sh /etc/rc.common
# shellcheck disable=SC2034,SC2154

START=99
USE_PROCD=1

script=$(readlink "$initscript")
NAME="$(basename ${script:-$initscript})"
CONFIG_NAME="podkop-plus"
PODKOP_BIN="/usr/bin/podkop-plus"
PODKOP_SERVICE_INIT="/etc/init.d/podkop-plus"
PODKOP_RELOAD_LOCK_DIR="/var/run/podkop-plus.reload.lock"
PODKOP_RUNTIME_STATE_DIR="/var/run/podkop-plus"
PODKOP_PENDING_RELOAD_FILE="$PODKOP_RUNTIME_STATE_DIR/reload.pending"
PODKOP_INTERNAL_CONFIG_TRIGGER_GUARD="/var/run/podkop-plus.internal-config-change"
PODKOP_CONFIG_CHANGE_REASON="on_config_change"
config_load "$CONFIG_NAME"

acquire_reload_lock() {
    local owner_pid

    if mkdir "$PODKOP_RELOAD_LOCK_DIR" 2> /dev/null; then
        printf '%s\n' "$$" > "$PODKOP_RELOAD_LOCK_DIR/pid"
        return 0
    fi

    owner_pid="$(sed -n '1p' "$PODKOP_RELOAD_LOCK_DIR/pid" 2> /dev/null)"
    if [ -n "$owner_pid" ] && kill -0 "$owner_pid" 2> /dev/null; then
        return 1
    fi

    rm -f "$PODKOP_RELOAD_LOCK_DIR/pid" 2> /dev/null
    rmdir "$PODKOP_RELOAD_LOCK_DIR" 2> /dev/null || return 1
    mkdir "$PODKOP_RELOAD_LOCK_DIR" 2> /dev/null || return 1
    printf '%s\n' "$$" > "$PODKOP_RELOAD_LOCK_DIR/pid"
}

release_reload_lock() {
    rm -f "$PODKOP_RELOAD_LOCK_DIR/pid" 2> /dev/null
    rmdir "$PODKOP_RELOAD_LOCK_DIR" 2> /dev/null
}

mark_pending_reload() {
    local reason="${1:-pending}"
    local now

    mkdir -p "$PODKOP_RUNTIME_STATE_DIR"
    now="$(date +%s 2>/dev/null)"
    case "$now" in
        '' | *[!0-9]*)
            now=0
            ;;
    esac

    {
        printf 'reason=%s\n' "$reason"
        printf 'updated_at=%s\n' "$now"
    } > "$PODKOP_PENDING_RELOAD_FILE"
}

consume_pending_reload() {
    [ -f "$PODKOP_PENDING_RELOAD_FILE" ] || return 1
    rm -f "$PODKOP_PENDING_RELOAD_FILE" 2>/dev/null
}

run_pending_reload_if_requested() {
    consume_pending_reload || return 0
    "$PODKOP_SERVICE_INIT" reload pending >/dev/null 2>&1 &
}

sync_service_triggers() {
    config_load "$CONFIG_NAME"
    _procd_call sync_service_triggers_payload
}

sync_service_triggers_payload() {
    # rc.common registers triggers when the service is started. Config reloads can
    # change Bad WAN interface triggers, so refresh the trigger set after a
    # successful config-change reload without restarting the runtime.
    json_init
    json_add_string name "$NAME"
    service_triggers
    _procd_ubus_call set > /dev/null 2>&1 || true
}

is_config_change_reload() {
    [ "$1" = "$PODKOP_CONFIG_CHANGE_REASON" ]
}

runtime_is_running() {
    "$PODKOP_BIN" get_status 2> /dev/null | grep -q '"running":1'
}

service_is_enabled() {
    [ -x "/etc/rc.d/S99$NAME" ]
}

consume_internal_config_guard() {
    rm -f "$PODKOP_INTERNAL_CONFIG_TRIGGER_GUARD" 2> /dev/null
}

internal_config_guard_is_recent() {
    local now guard_timestamp

    guard_timestamp="$(sed -n '1p' "$PODKOP_INTERNAL_CONFIG_TRIGGER_GUARD" 2>/dev/null)"
    case "$guard_timestamp" in
        '' | *[!0-9]*)
            return 1
            ;;
    esac

    now="$(date +%s 2>/dev/null)"
    case "$now" in
        '' | *[!0-9]*)
            return 0
            ;;
    esac

    [ $((now - guard_timestamp)) -le 30 ]
}

should_skip_internal_config_reload() {
    local reason="$1"

    [ "$reason" = "on_config_change" ] || return 1
    [ -f "$PODKOP_INTERNAL_CONFIG_TRIGGER_GUARD" ] || return 1

    if internal_config_guard_is_recent; then
        consume_internal_config_guard
        return 0
    fi

    consume_internal_config_guard

    return 1
}

start_service() {
    echo "Start Podkop Plus"

    config_get enable_badwan_interface_monitoring "settings" "enable_badwan_interface_monitoring"
    config_get badwan_monitored_interfaces "settings" "badwan_monitored_interfaces"

    procd_open_instance
    procd_set_param command "$PODKOP_BIN" start
    [ "$enable_badwan_interface_monitoring" = "1" ] && [ -n "$badwan_monitored_interfaces" ] &&
        procd_set_param netdev "$badwan_monitored_interfaces"
    procd_set_param stdout 1
    procd_set_param stderr 1
    procd_close_instance
}

stop_service() {
    "$PODKOP_BIN" stop
}

reload_service() {
    local reason="$1"

    if should_skip_internal_config_reload "$reason"; then
        return 0
    fi

    if is_config_change_reload "$reason" && ! runtime_is_running && ! service_is_enabled; then
        return 0
    fi

    if ! acquire_reload_lock; then
        mark_pending_reload "${reason:-reload_busy}"
        return 0
    fi

    trap 'release_reload_lock' EXIT INT TERM
    "$PODKOP_BIN" reload "$reason" > /dev/null 2>&1
    local status="$?"
    if [ "$status" -eq 0 ] && is_config_change_reload "$reason"; then
        sync_service_triggers
    fi
    trap - EXIT INT TERM
    release_reload_lock
    run_pending_reload_if_requested

    return "$status"
}

status_service() {
    if "$PODKOP_BIN" get_status 2> /dev/null | grep -q '"running":1'; then
        echo "running"
        return 0
    fi

    echo "not running"
    return 1
}

service_triggers() {
    config_get enable_badwan_interface_monitoring "settings" "enable_badwan_interface_monitoring"
    config_get badwan_monitored_interfaces "settings" "badwan_monitored_interfaces"
    config_get badwan_reload_delay "settings" "badwan_reload_delay" "2000"

    PROCD_RELOAD_DELAY=$badwan_reload_delay

    procd_open_trigger
    procd_add_config_trigger "config.change" "$CONFIG_NAME" "$PODKOP_SERVICE_INIT" reload "$PODKOP_CONFIG_CHANGE_REASON"

    if [ "$enable_badwan_interface_monitoring" = "1" ]; then
        for iface in $badwan_monitored_interfaces; do
            procd_add_interface_trigger "interface.*.up" "$iface" "$PODKOP_SERVICE_INIT" reload
        done
    fi
    procd_close_trigger
}
