# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

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

# This wrapper is a drop-in replacement for espeak, which does the following:
# 1. If the language is not Japanese, it calls espesk from the system directly.
# 2. If the language is Japanese, it calls open_jtalk. Models and voice are
#   provided in the japanese/ folder. They're licensed under BSD-3-Clause, so
#   we can redistribute them with the game.
# 3. If open_jtalk is not available, fall back to espeak.

ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"

REAL_ESPEAK="$(command -v espeak-ng || true)"
if [[ -z "${REAL_ESPEAK}" ]]; then
  REAL_ESPEAK="$(command -v /usr/bin/espeak || command -v espeak)"
fi

if [[ -z "${REAL_ESPEAK}" ]]; then
  echo "ERROR: could not find espeak or espeak-ng in PATH" >&2
  exit 127
fi

OPENJTALK="$(command -v open_jtalk || true)"
if [[ -z "${OPENJTALK}" ]]; then
  echo "WARNING: could not find open_jtalk in PATH" >&2
  echo "Falling back to espeak for all languages, including Japanese." >&2
fi

PLAYER="$(command -v paplay || command -v aplay || true)"
if [[ -z "${PLAYER}" ]]; then
  echo "WARNING: could not find paplay or aplay in PATH" >&2
  echo "Falling back to espeak for all languages, including Japanese." >&2
fi

JTALK_DIC="${ROOT}/japanese/dict"
JTALK_VOICE="${ROOT}/japanese/voice/nitech_jp_atr503_m001.htsvoice"

voice=""
declare -a passthrough=()
text=""

while (($#)); do
  case "$1" in
    -v)
      shift
      voice="${1:-}"
      ;;
    -v*)
      voice="${1#-v}"
      ;;
    # keep other flags for espeak fallback (-a is used by Ren'Py)
    -*)
      passthrough+=("$1")
      # capture arg for flags like -a <amp>
      if [[ "$1" == "-a" && $# -ge 2 ]]; then
        shift
        passthrough+=("$1")
      fi
      ;;
    *)
      # Ren'Py appends the full text as one argument.
      # If something else adds extra args, last one wins.
      text="$1"
      ;;
  esac
  shift || true
done


fallback() {
  echo "ERROR: OpenJTalk failed; falling back to espeak" >&2
}

voice_openjtalk() {
  [[ -n "${OPENJTALK}" && -x "${OPENJTALK}" ]] || return 2
  [[ -d "${JTALK_DIC}" ]] || return 3
  [[ -f "${JTALK_VOICE}" ]] || return 4
  [[ -n "${text}" ]] || return 5

  local tmpwav
  tmpwav="$(mktemp --suffix=.wav)"

  set +e
  printf "%s" "${text}" | "${OPENJTALK}" \
    -x "${JTALK_DIC}" \
    -m "${JTALK_VOICE}" \
    -ow "${tmpwav}" \
    >/dev/null 2>&1
  local rc=$?
  set -e

  # If a generated wav file is empty, fallback.
  if [[ $rc -ne 0 || ! -s "${tmpwav}" ]]; then
    rm -f "${tmpwav}"
    return 10
  fi

  # If there is no player, fallback to espeak.
  if [[ -z "${PLAYER}" ]]; then
    rm -f "${tmpwav}"
    return 11
  fi

  set +e
  "${PLAYER}" "${tmpwav}" >/dev/null 2>&1
  local prc=$?
  set -e

  rm -f "${tmpwav}"
  [[ $prc -eq 0 ]] || return 12

  return 0
}

if [[ "${voice}" == "ja" ]]; then
  if voice_openjtalk; then
    exit 0
  else
    fallback
  fi
fi

# Fallback to espeak.
if [[ -n "${voice}" ]]; then
  exec "${REAL_ESPEAK}" -v "${voice}" "${passthrough[@]}" "${text}"
else
  exec "${REAL_ESPEAK}" "${passthrough[@]}" "${text}"
fi
