#!/bin/bash
# ПО «Ловчий. Распознание и наведение» 1.0 · ООО «Нейротех» · запуск
#
#   lovchiy --sim                                      -- режим имитации: виртуальная поворотная камера на тестовом видео
#   lovchiy --sim=/путь/к/широкому_видео.mp4           -- то же на своём широкоугольном видео
#   lovchiy --sim=... --sim-args="--fov-frac=0.5 --hfov=54"   -- ключи имитатора (размер окна, угол обзора исхода)
#   lovchiy --url1=rtsp://ip:554/stream --ptz1=onvif://admin@ip:80   -- камера RTSP и поворотная платформа ONVIF
#   lovchiy --input1=/путь/к/видео.mp4                 -- только обнаружение на видеофайле
#   lovchiy --server ...                               -- без окна (сервер), журнал событий в протоколе
#
# Ключи по умолчанию -- в /etc/lovchiy/lovchiy.conf. Любой ключ программы можно добавить в командную
# строку, он заменит значение из файла настроек. Основные ключи наведения:
#   --ptz1..--ptz4=onvif://логин@адрес:порт   платформа канала (пароль -- PTZ_PASSWORD в настройках)
#   --ptz-mode=auto|manual|off                 автоматическое наведение / только оператор / выключено
#   --ptz-profile=<token>                      профиль ONVIF
#   --ptz-deadzone=0.05 --ptz-kp=1.6 --ptz-ki=0.4 --ptz-lost=5 --ptz-home=<preset>
#   --backend=auto|cpu|gpu --profile=cpu640|cpu1280|cpu1280-int8 --thr=0.6 --cpu-threads=N
set -e
CONF=/etc/lovchiy/lovchiy.conf
[ -r "$CONF" ] && . "$CONF"
UCONF=${HOME:-/nonexistent}/.config/lovchiy/lovchiy.conf   # личные настройки и секреты
[ -r "$UCONF" ] && . "$UCONF"
PROFILE=${PROFILE:-cpu640}; BACKEND=${BACKEND:-auto}; THR=${THR:-0.6}; UI=${UI:-sciter}
B=/opt/lovchiy/bin; S=/opt/lovchiy/share

ARGS=(); HAS=" "; SIM=""
add_arg() { ARGS+=("$1"); HAS="$HAS${1%%=*} "; }
abspath() { if [ "$1" != none ] && [ "${1#/}" = "$1" ] && [ -e "$1" ]; then readlink -f "$1"; else echo "$1"; fi; }
for a in "$@"; do
  case "$a" in
    --server) UI=none ;;
    --profile=*) PROFILE="${a#--profile=}" ;;
    --sim) SIM="${SIM_SOURCE:-$S/test/wide_a_h264.mp4}" ;;
    --sim=*) SIM="$(abspath "${a#--sim=}")" ;;
    --sim-args=*) SIM_ARGS="${a#--sim-args=}" ;;
    --input[0-9]*=*) add_arg "${a%%=*}=$(abspath "${a#*=}")" ;;
    *) add_arg "$a" ;;
  esac
done

WORK=${LOVCHIY_WORK:-${HOME:-/tmp}/.local/share/lovchiy}
mkdir -p "$WORK/alarms" "$WORK/logs"

# ---- режим имитации: локальная служба lovchiy-ptz-sim (127.0.0.1:8899, RTSP 8556) ----
SIM_PID=""
if [ -n "$SIM" ]; then
  # ключи имитатора для конкретного видео -- в файле рядом с ним: <видео>.sim (например, --start-pan=28 --start-tilt=-4)
  [ -z "$SIM_ARGS" ] && [ -r "$SIM.sim" ] && SIM_ARGS="$(grep -v '^#' "$SIM.sim" | tr '\n' ' ')"
  export LOVCHIY_SIM_PASSWORD="${SIM_PASSWORD:-lovchiy}" LOVCHIY_PTZ_PASSWORD="${SIM_PASSWORD:-lovchiy}"
  if (exec 3<>/dev/tcp/127.0.0.1/8899) 2>/dev/null; then
    echo "Служба имитации уже работает на 127.0.0.1:8899 -- подключаюсь к ней"
  else
    [ -e "$SIM" ] || [ "${SIM#rtsp://}" != "$SIM" ] || { echo "Нет видео для имитации: $SIM"; exit 1; }
    read -r -a SA <<< "${SIM_ARGS:-}"
    "$B/lovchiy-ptz-sim" --source="$SIM" "${SA[@]}" --quiet > "$WORK/logs/ptz-sim.log" 2>&1 &
    SIM_PID=$!
    for i in $(seq 1 40); do (exec 3<>/dev/tcp/127.0.0.1/8899) 2>/dev/null && break; sleep 0.25; done
    kill -0 $SIM_PID 2>/dev/null || { echo "Служба имитации не запустилась:"; cat "$WORK/logs/ptz-sim.log"; exit 1; }
    echo "Служба имитации запущена: $(grep -a 'исходное видео' "$WORK/logs/ptz-sim.log" | sed 's/^.*ptz-sim: //')"
  fi
  case "$HAS" in *" --url1 "*|*" --input1 "*) ;; *) add_arg "--url1=rtsp://127.0.0.1:8556/ptz";; esac
  add_arg "--ptz-sim"
  case "$HAS" in *" --ptz-hfov "*) ;; *) add_arg "--ptz-hfov=27";; esac        # окно имитатора: 30 % от 90°
  case "$HAS" in *" --ptz-vmax-deg "*) ;; *) add_arg "--ptz-vmax-deg=60";; esac
else
  [ -n "$PTZ_PASSWORD" ] && export LOVCHIY_PTZ_PASSWORD="$PTZ_PASSWORD"
fi

# источник из настроек, если в командной строке его нет
case "$HAS" in *" --input1 "*|*" --url1 "*|*" --gige1 "*) ;; *)
  if [ -n "$SOURCE" ]; then read -r -a SRC <<< "$SOURCE"; for a in "${SRC[@]}"; do add_arg "$a"; done
  else
    echo "Укажите источник: --sim (режим имитации), --url1=rtsp://... или --input1=видеофайл (или SOURCE в $CONF)"
    [ -t 0 ] && read -r -t 30 _ || true
    exit 1
  fi;;
esac

cd "$WORK"
if [ "$UI" = sciter ] && [ ! -f $B/libsciter-gtk.so ]; then
  echo "Окно оператора не установлено (пакет lovchiy-gui) -- запуск без окна"; UI=none; fi
if [ "$UI" = sciter ] && [ -z "$DISPLAY" ] && [ -z "$WAYLAND_DISPLAY" ]; then
  echo "Нет графического сеанса -- запуск без окна"; UI=none; fi

DEF=(--onnx --zoo=$S/models.yml --html=$S/ui/lovchiy.html --ignore-empty)
opt() { case "$HAS" in *" $1 "*) ;; *) [ -n "$2" ] && DEF+=("$1=$2");; esac; return 0; }
opt --backend "$BACKEND"; opt --thr "$THR"; opt --ui "$UI"; opt --alarms-rate "${ALARMS_RATE:-1000}"
for n in 2 3 4; do
  case "$HAS" in *" --url$n "*|*" --input$n "*) ;; *) DEF+=(--input$n=none);; esac
done
# наведение -- из настроек, если не задано в командной строке
if [ -z "$SIM" ]; then for n in 1 2 3 4; do v="PTZ$n"; opt --ptz$n "${!v}"; done; fi
opt --ptz-mode "$PTZ_MODE"; opt --ptz-profile "$PTZ_PROFILE"; opt --ptz-deadzone "$PTZ_DEADZONE"
opt --ptz-kp "$PTZ_KP"; opt --ptz-ki "$PTZ_KI"; opt --ptz-vmax "$PTZ_VMAX"; opt --ptz-confirm "$PTZ_CONFIRM"
opt --ptz-min-score "$PTZ_MIN_SCORE"; opt --ptz-lost "$PTZ_LOST"; opt --ptz-home "$PTZ_HOME"
if [ -z "$SIM" ]; then opt --ptz-hfov "$PTZ_HFOV"; [ "${PTZ_VMAX_DEG:-0}" != 0 ] && opt --ptz-vmax-deg "$PTZ_VMAX_DEG"; fi
case "$HAS" in *" --ptz-log "*) ;; *) DEF+=(--ptz-log="$WORK/logs/ptz_$(date +%Y%m%d_%H%M%S).csv");; esac
# оповещения: секреты -- только через окружение, не в командной строке (её видно в ps)
export LOVCHIY_TG_TOKEN="${TG_TOKEN:-$LOVCHIY_TG_TOKEN}" LOVCHIY_TG_API="${TG_API:-$LOVCHIY_TG_API}" LOVCHIY_TG_PROXY="${TG_PROXY:-$LOVCHIY_TG_PROXY}"
export LOVCHIY_MAX_TOKEN="${MAX_TOKEN:-$LOVCHIY_MAX_TOKEN}" LOVCHIY_MAX_API="${MAX_API:-$LOVCHIY_MAX_API}"
export LOVCHIY_SMSC_LOGIN="${SMSC_LOGIN:-$LOVCHIY_SMSC_LOGIN}" LOVCHIY_SMSC_PASSWORD="${SMSC_PASSWORD:-$LOVCHIY_SMSC_PASSWORD}"
case "$HAS" in *" --bot "*) ;; *) [ -n "$BOT_CHAT" ] && DEF+=(--bot="$BOT_CHAT");; esac
case "$HAS" in *" --max "*) ;; *) [ -n "$MAX_CHAT" ] && DEF+=(--max="$MAX_CHAT");; esac
case "$HAS" in *" --sms "*) ;; *) [ -n "$SMS_PHONE" ] && DEF+=(--sms="$SMS_PHONE");; esac
[ -n "$EXTRA" ] && read -r -a EX <<< "$EXTRA" && DEF+=("${EX[@]}")

if [ -z "$SIM_PID" ]; then exec $B/lovchiy "${DEF[@]}" "${ARGS[@]}" "$PROFILE"; fi
# имитатор запущен этой командой -- остановить его после выхода программы
trap 'kill $SIM_PID 2>/dev/null; wait $SIM_PID 2>/dev/null' EXIT
trap 'kill -INT $LV_PID 2>/dev/null' INT TERM
set +e
$B/lovchiy "${DEF[@]}" "${ARGS[@]}" "$PROFILE" &
LV_PID=$!
wait $LV_PID; rc=$?
[ $rc -gt 128 ] && kill -0 $LV_PID 2>/dev/null && { wait $LV_PID; rc=$?; }
exit $rc
