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

# c411encode.sh
# Author: SteGarsLa
# Version: 1.0 - Imperial Baseline
# Description: C411-compliant encoder with DTS preservation + AC3 fallback

INPUT="${1:-}"
[[ -z "$INPUT" || ! -f "$INPUT" ]] && { echo "Usage: $0 \"film.mkv\""; exit 1; }

command -v mediainfo >/dev/null || { echo "Manquant: mediainfo"; exit 1; }
command -v ffprobe >/dev/null || { echo "Manquant: ffprobe"; exit 1; }
command -v iconv >/dev/null || { echo "Manquant: iconv"; exit 1; }

echo
echo "========================================"
echo "   Générateur de NFO de SteGarsLa"
echo "   SteGarsLa's NFO Generator"
echo "   Compatible C411 / C411 Compliant"
echo "========================================"
echo "Mode            : Analyse seule (aucun encodage)"
echo "Fichier         : $INPUT"
echo "Pipeline audio  : Copy; DTS/DCA -> AC3 640k si nécessaire"
echo "========================================"
echo

ask(){ local v; read -rp "$1: " v; echo "$v"; }

choose() {
  local prompt="$1"; shift
  local opts=("$@") n
  {
    echo
    echo "$prompt"
    for i in "${!opts[@]}"; do echo "  $((i+1))) ${opts[$i]}"; done
  } > /dev/tty

  while true; do
    read -rp "Choix: " n < /dev/tty
    [[ "$n" =~ ^[0-9]+$ ]] && (( n>=1 && n<=${#opts[@]} )) && {
      echo "${opts[$((n-1))]}"
      return
    }
    echo "Choix invalide." > /dev/tty
  done
}

sanitize() {
  echo "$1" \
    | iconv -f UTF-8 -t ASCII//TRANSLIT 2>/dev/null \
    | sed -E 's/[^A-Za-z0-9]+/./g; s/^\.//; s/\.$//; s/\.+/./g'
}

is_french() {
  [[ "${1,,}" =~ ^fr$|^fra$|^fre$|french|français|francais ]]
}

is_non_empty_lang() {
  [[ -n "${1:-}" && "${1,,}" != "und" && "${1,,}" != "unknown" ]]
}

ch_tag() {
  case "$1" in
    8) echo "7.1" ;;
    6) echo "5.1" ;;
    2) echo "2.0" ;;
    1) echo "1.0" ;;
    *) echo "${1}ch" ;;
  esac
}

codec_tag() {
  case "${1,,}" in
    ac3|ac-3) echo "AC3" ;;
    eac3|e-ac-3) echo "EAC3" ;;
    aac) echo "AAC" ;;
    mp3) echo "MP3" ;;
    dts|dca) echo "DTS" ;;
    flac) echo "FLAC" ;;
    truehd) echo "TRUEHD" ;;
    pcm*) echo "PCM" ;;
    *) echo "$1" | tr '[:lower:]' '[:upper:]' ;;
  esac
}

video_tag() {
  local codec="$1"
  case "${codec,,}" in
    hevc|h265|h.265) echo "x265" ;;
    h264|h.264|avc) echo "x264" ;;
    mpeg2video) echo "MPEG2" ;;
    mpeg4) echo "XviD" ;;
    *) echo "$(sanitize "$codec")" ;;
  esac
}

detect_vf_type_hint() {
  local haystack
  haystack="$(printf "%s\n%s\n" \
    "$(basename "$INPUT")" \
    "$(mediainfo --Inform="Audio;%Title%\n" "$INPUT")" \
    | tr '[:lower:]' '[:upper:]')"

  if echo "$haystack" | grep -Eq '(^|[^A-Z0-9])VFI([^A-Z0-9]|$)'; then echo "VFI"; return; fi
  if echo "$haystack" | grep -Eq '(^|[^A-Z0-9])VFF([^A-Z0-9]|$)'; then echo "VFF"; return; fi
  if echo "$haystack" | grep -Eq '(^|[^A-Z0-9])VFQ([^A-Z0-9]|$)'; then echo "VFQ"; return; fi
  if echo "$haystack" | grep -Eq '(^|[^A-Z0-9])VF2([^A-Z0-9]|$)'; then echo "VF2"; return; fi
  echo ""
}

detect_language_tag() {
  local has_fr=0 has_other=0 vf_hint lang

  while IFS='|' read -r lang; do
    if is_french "${lang:-}"; then
      has_fr=1
    elif is_non_empty_lang "${lang:-}"; then
      has_other=1
    fi
  done < <(
    ffprobe -v error -select_streams a \
      -show_entries stream_tags=language \
      -of compact=p=0:nk=1 "$INPUT"
  )

  vf_hint="$(detect_vf_type_hint)"

  if (( has_fr == 1 )); then
    if [[ -z "$vf_hint" ]]; then
      vf_hint="$(choose "Type de VF détectée mais non identifiée" "VFF" "VFQ" "VFI" "VF2")"
    fi

    if (( has_other == 1 )); then
      LANG="MULTI.$vf_hint"
    else
      LANG="$vf_hint"
    fi
  else
    if (( has_other == 1 )); then
      LANG="$(choose "Aucune VF détectée. Type de release" "VO" "VOSTFR")"
    else
      LANG="$(choose "Langue release" "VFF" "VFQ" "VFI" "VF2" "MULTI.VFF" "MULTI.VFQ" "MULTI.VFI" "MULTI.VF2" "VO" "VOSTFR")"
    fi
  fi

  echo "Langue détectée/choisie: $LANG" > /dev/tty
}

analyze_audio() {
  MAX_CH=0
  MAX_FR_CH=0
  HAS_FR=0
  HAS_LOSSLESS=0
  SELECTED_CODEC=""

  while IFS='|' read -r codec ch lang; do
    [[ -z "${ch:-}" ]] && continue
    [[ "$ch" =~ ^[0-9]+$ ]] || continue

    (( ch > MAX_CH )) && MAX_CH="$ch"

    if [[ "${codec,,}" =~ flac|truehd|mlp|pcm|dts_hd|dts-hd ]]; then
      HAS_LOSSLESS=1
    fi

    if is_french "${lang:-}"; then
      HAS_FR=1
      if (( ch > MAX_FR_CH )); then
        MAX_FR_CH="$ch"
        SELECTED_CODEC="$codec"
      fi
    fi
  done < <(
    ffprobe -v error -select_streams a \
      -show_entries stream=codec_name,channels:stream_tags=language \
      -of compact=p=0:nk=1 "$INPUT"
  )

  if (( HAS_LOSSLESS == 1 )); then
    AUDIO_MODE="LOSSLESS"
    FINAL_CH="$MAX_CH"

    while IFS='|' read -r codec ch lang; do
      [[ -z "${ch:-}" ]] && continue
      [[ "$ch" =~ ^[0-9]+$ ]] || continue
      if (( ch == FINAL_CH )); then
        SELECTED_CODEC="$codec"
        break
      fi
    done < <(
      ffprobe -v error -select_streams a \
        -show_entries stream=codec_name,channels:stream_tags=language \
        -of compact=p=0:nk=1 "$INPUT"
    )
  else
    AUDIO_MODE="LOSSY"
    if (( HAS_FR == 1 )); then
      FINAL_CH="$MAX_FR_CH"
    else
      FINAL_CH="$MAX_CH"

      while IFS='|' read -r codec ch lang; do
        [[ -z "${ch:-}" ]] && continue
        [[ "$ch" =~ ^[0-9]+$ ]] || continue
        if (( ch == FINAL_CH )); then
          SELECTED_CODEC="$codec"
          break
        fi
      done < <(
        ffprobe -v error -select_streams a \
          -show_entries stream=codec_name,channels:stream_tags=language \
          -of compact=p=0:nk=1 "$INPUT"
      )
    fi
  fi

  CHANNEL_TAG="$(ch_tag "$FINAL_CH")"
  AUDIO_CODEC_TAG="$(codec_tag "$SELECTED_CODEC")"
}

correct_mediainfo_subs() {
  local file="$1"

  mediainfo "$file" | awk '
    function is_image_sub() {
      return (fmt ~ /VobSub|PGS|HDMV PGS/)
    }

    function num_from_line(s) {
      sub(/^.*:[ \t]*/, "", s)
      gsub(/[^0-9]/, "", s)
      return s + 0
    }

    function should_force() {
      if (!is_image_sub()) return 0
      if (count > 0 && count < 100) return 1
      if (count == 0 && bitrate > 0 && bitrate < 100) return 1
      return 0
    }

    function flush_text_block(   i, forceit, line) {
      if (!intext) return

      forceit = should_force()

      for (i = 1; i <= n; i++) {
        line = block[i]

        if (line ~ /^Format[ \t]*:/ && line ~ /UTF-8/) {
          print "Format                                   : SRT"
        }
        else if (line ~ /^Forced[ \t]*:/) {
          if (forceit) print "Forced                                   : Yes"
          else print "Forced                                   : No"
        }
        else {
          print line
        }
      }

      intext=0
      n=0
      fmt=""
      bitrate=0
      count=0
    }

    /^Text #[0-9]+/ {
      flush_text_block()
      intext=1
      n=0
      fmt=""
      bitrate=0
      count=0
      block[++n]=$0
      next
    }

    /^Menu/ {
      flush_text_block()
      print
      next
    }

    intext {
      block[++n]=$0

      if ($0 ~ /^Format[ \t]*:/) {
        fmt=$0
      }
      else if ($0 ~ /^Bit rate[ \t]*:/) {
        bitrate=num_from_line($0)
      }
      else if ($0 ~ /^Count of elements[ \t]*:/) {
        count=num_from_line($0)
      }

      next
    }

    {
      print
    }

    END {
      flush_text_block()
    }
  '
}

clean_nfo_video_metrics() {
  awk '
    /^Video$/ { in_video=1; print; next }
    /^(Audio|Text|Menu)( #[0-9]+)?$/ { in_video=0; print; next }

    in_video && /^Bit rate[ \t]*:/ { next }
    in_video && /^Stream size[ \t]*:/ { next }

    { print }
  '
}

echo "=== Infos film / tracker ==="

TITLE="$(ask "Title")"
TITLE_CLEAN="$(sanitize "$TITLE")"

read -rp "OriginalTitle identique? [O/n]: " SAME
[[ "$SAME" =~ ^[Nn]$ ]] && ORIGINAL="$(ask "OriginalTitle")" || ORIGINAL="$TITLE"

YEAR="$(ask "Année")"
TMDB="$(ask "TMDB ID seulement les chiffres")"

CRF="$(ask "CRF (laisser vide si inconnu)")"

if [[ -n "$CRF" ]]; then
  PRESET="$(ask "Preset (laisser vide si inconnu)")"
else
  PRESET=""
fi

SOURCE_BASE="$(choose "Source" "DVD" "BluRay" "Web-DL" "HDTV")"
FPS="$(mediainfo --Inform="Video;%FrameRate%" "$INPUT")"

if [[ "$SOURCE_BASE" == "DVD" ]]; then
  SOURCE_NAME="DVDRip"

  # On garde l’info pour analyse interne seulement (pas dans le filename)
  if awk "BEGIN {exit !($FPS > 24.5 && $FPS < 25.5)}"; then
    DVD_SYSTEM="PAL"
  else
    DVD_SYSTEM="NTSC"
  fi
else
  SOURCE_NAME="$(sanitize "$SOURCE_BASE")"
  DVD_SYSTEM=""
fi

detect_language_tag
analyze_audio

VIDEO_CODEC="$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$INPUT")"
VIDEO_TAG="$(video_tag "$VIDEO_CODEC")"

OUT="${TITLE_CLEAN}.${YEAR}.${LANG}.${SOURCE_NAME}.${AUDIO_CODEC_TAG}.${CHANNEL_TAG}.${VIDEO_TAG}-SteGarsLa.nfo"

correct_mediainfo_subs "$INPUT" \
| clean_nfo_video_metrics \
| sed -E "s|^Complete name[[:space:]]*:.*|Complete name                            : ${OUT%.nfo}.mkv|" \
| awk -v title="$ORIGINAL" -v tmdb="$TMDB" -v crf="$CRF" -v preset="$PRESET" '
/^General$/ {
  print
  print "Title                                    : " title
  print "TMDB                                     : https://www.themoviedb.org/movie/"tmdb

  if (preset != "") {
    print "Encoding preset                          : " preset
  }

  if (crf != "") {
    print "Encoding CRF                             : " crf
  }

  print "Encoding audio                           : Copy; DTS/DCA -> AC3 640k only if no same-language non-DTS track exists"
  print "Generated by                             : SteGarsLa // c411nfo.sh"
  next
}
{ print }
' > "$OUT"

echo
echo "NFO généré:"
echo "$OUT"
