#!/usr/bin/env bash
set -euo pipefail

script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
export NOISM_APP_DIR="${NOISM_APP_DIR:-$script_dir}"

# shellcheck disable=SC1090
source "$script_dir/noism.sh" >/dev/null 2>&1

runtime_root="$_noism_runtime_root"
state_file="$_noism_state_file"
control_fifo="$runtime_root/control"
player_pid=""
mpris_pid=""
shutdown_requested=0

usage() {
  cat <<'EOF'
Usage: noism-channel [track] [volume]

Run the Noism controller for one track. Media keys and MPRIS commands talk to
this controller through a FIFO in the runtime directory.
EOF
}

write_inactive_state() {
  mkdir -p "$runtime_root"
  {
    printf 'NOISM_APP_DIR=%q\n' "$_noism_app_dir"
    printf 'NOISM_SHELL_PID=%q\n' ""
    printf 'NOISM_FFPLAY_PID=%q\n' ""
    printf 'NOISM_PLAY_STATE=%q\n' "${_NOISM_PLAY_STATE:-stopped}"
    printf 'NOISM_ACTIVE_TRACK=%q\n' "${_NOISM_ACTIVE_TRACK:-}"
    printf 'NOISM_ACTIVE_VOLUME=%q\n' "${_NOISM_ACTIVE_VOLUME:-$_noism_default_volume}"
    printf 'NOISM_ACTIVE_CROSSFADE=%q\n' "${_NOISM_ACTIVE_CROSSFADE:-}"
  } >"$state_file"
}

adjacent_track() {
  local direction="$1"
  local current="${_NOISM_ACTIVE_TRACK:-}"
  local i count

  _noism_load_tracks 'All' || return 1
  count="${#NOISM_TRACKS[@]}"
  (( count > 0 )) || return 1

  if [[ -z "$current" ]]; then
    printf '%s\n' "${NOISM_TRACKS[0]}"
    return 0
  fi

  for i in "${!NOISM_TRACKS[@]}"; do
    if [[ "${NOISM_TRACKS[$i]}" == "$current" ]]; then
      if [[ "$direction" == "next" ]]; then
        printf '%s\n' "${NOISM_TRACKS[$(((i + 1) % count))]}"
      else
        printf '%s\n' "${NOISM_TRACKS[$(((i - 1 + count) % count))]}"
      fi
      return 0
    fi
  done

  printf '%s\n' "${NOISM_TRACKS[0]}"
}

stop_player() {
  local reason="${1:-stopped}"

  if [[ -n "${player_pid:-}" ]] && _noism_pid_is_running "$player_pid"; then
    _noism_terminate_pid "$player_pid"
    wait "$player_pid" 2>/dev/null || true
  fi

  player_pid=""
  _NOISM_FFPLAY_PID=""
  _NOISM_PLAY_STATE="stopped"
  _NOISM_ACTIVE_RENDER_FILE=""

  case "$reason" in
    exit)
      write_inactive_state
      ;;
    *)
      _noism_write_runtime_state
      ;;
  esac
}

stop_mpris_bridge() {
  if [[ -n "${mpris_pid:-}" ]] && _noism_pid_is_running "$mpris_pid"; then
    _noism_terminate_pid "$mpris_pid"
    wait "$mpris_pid" 2>/dev/null || true
  fi
  mpris_pid=""
}

start_mpris_bridge() {
  local pid

  stop_mpris_bridge
  while read -r pid; do
    [[ -n "$pid" ]] || continue
    _noism_terminate_pid "$pid"
  done < <(pgrep -u "$USER" -f "^python3 $script_dir/noism-mpris$" 2>/dev/null || true)

  "$script_dir/noism-mpris" >/dev/null 2>&1 </dev/null &
  mpris_pid=$!
}

start_player() {
  local track_name="${1:-${_NOISM_ACTIVE_TRACK:-$_noism_default_track}}"
  local requested_volume="${2:-${_NOISM_ACTIVE_VOLUME:-$_noism_default_volume}}"

  _noism_prepare_playback "$track_name" "$requested_volume" || {
    echo "$_NOISM_ERROR_MESSAGE" >&2
    return 1
  }

  stop_player restart

  ffplay \
    -hide_banner \
    -loglevel error \
    -nostats \
    -nodisp \
    -autoexit \
    -noinfbuf \
    -volume "$_NOISM_PREP_VOLUME" \
    -loop 0 \
    "$_NOISM_PREP_RENDER_FILE" >/dev/null 2>&1 </dev/null &

  player_pid=$!
  _NOISM_FFPLAY_PID="$player_pid"
  _NOISM_ACTIVE_TRACK="$_NOISM_PREP_TRACK_SLUG"
  _NOISM_ACTIVE_VOLUME="$_NOISM_PREP_VOLUME"
  _NOISM_ACTIVE_CROSSFADE="$_NOISM_PREP_CROSSFADE"
  _NOISM_ACTIVE_RENDER_FILE="$_NOISM_PREP_RENDER_FILE"
  _NOISM_PLAY_STATE="playing"
  _noism_write_runtime_state
}

pause_player() {
  [[ -n "${player_pid:-}" ]] || return 1
  _noism_pid_is_running "$player_pid" || return 1
  kill -STOP "$player_pid" 2>/dev/null || return 1
  _NOISM_PLAY_STATE="paused"
  _noism_write_runtime_state
}

resume_player() {
  [[ -n "${player_pid:-}" ]] || return 1
  _noism_pid_is_running "$player_pid" || return 1
  kill -CONT "$player_pid" 2>/dev/null || return 1
  _NOISM_PLAY_STATE="playing"
  _noism_write_runtime_state
}

handle_action() {
  local action="$1"
  local next_track=""

  case "$action" in
    play-pause)
      if [[ "$_NOISM_PLAY_STATE" == "paused" ]]; then
        resume_player || start_player
      elif [[ "$_NOISM_PLAY_STATE" == "playing" ]]; then
        pause_player || true
      else
        start_player
      fi
      ;;
    play)
      if [[ "$_NOISM_PLAY_STATE" == "paused" ]]; then
        resume_player || start_player
      elif [[ "$_NOISM_PLAY_STATE" != "playing" ]]; then
        start_player
      fi
      ;;
    pause)
      pause_player || true
      ;;
    stop|next|previous)
      return 0
      ;;
    *)
      return 1
      ;;
  esac
}

cleanup() {
  stop_mpris_bridge
  stop_player exit
  rm -f "$control_fifo"
}

if [[ "${1:-}" == "-h" || "${1:-}" == "--help" || "${1:-}" == "help" ]]; then
  usage
  exit 0
fi

track_name="${1:-$_noism_default_track}"
requested_volume="${2:-$_noism_default_volume}"

trap cleanup EXIT
trap 'shutdown_requested=1; exit 130' INT TERM

mkdir -p "$runtime_root"
rm -f "$control_fifo"
mkfifo "$control_fifo"
exec 3<>"$control_fifo"

_NOISM_ACTIVE_TRACK="$track_name"
_NOISM_ACTIVE_VOLUME="$requested_volume"
_NOISM_ACTIVE_CROSSFADE=""
_NOISM_PLAY_STATE="stopped"
_NOISM_FFPLAY_PID=""
_noism_write_runtime_state

start_player "$track_name" "$requested_volume"
start_mpris_bridge

while (( shutdown_requested == 0 )); do
  if [[ -n "${player_pid:-}" ]] && ! _noism_pid_is_running "$player_pid"; then
    wait "$player_pid" 2>/dev/null || true
    player_pid=""
    _NOISM_FFPLAY_PID=""
    _NOISM_PLAY_STATE="stopped"
    _NOISM_ACTIVE_RENDER_FILE=""
    shutdown_requested=1
    continue
  fi

  if IFS= read -r -t 0.2 action <&3; then
    [[ -n "$action" ]] || continue
    handle_action "$action" || true
  fi
done
