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

script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
. "$script_dir/common.sh"

usage() {
  cat <<'EOF'
Usage:
  merge-clips.sh [--dry-run] <output> <input1> <input2> [input3 ...]

Examples:
  merge-clips.sh merged.mp4 a.mp4 b.mp4
  merge-clips.sh merged.mp4 part1.mp4 part2.mp4 part3.mp4

Notes:
  This script is for already-compatible clips. It validates the first video and
  audio stream signatures, then uses the concat demuxer with stream copy.
EOF
}

video_signature() {
  ffprobe -v error -select_streams v:0 \
    -show_entries stream=codec_name,width,height,pix_fmt,r_frame_rate,time_base \
    -of csv=p=0 "$1" |
    sed -n '1p'
}

audio_signature() {
  if has_stream "$1" a:0; then
    ffprobe -v error -select_streams a:0 \
      -show_entries stream=codec_name,sample_rate,channel_layout,channels,time_base \
      -of csv=p=0 "$1" |
      sed -n '1p'
  else
    printf 'no-audio\n'
  fi
}

dry_run=0

while [ "$#" -gt 0 ]; do
  case "$1" in
    --dry-run)
      dry_run=1
      shift
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    --)
      shift
      break
      ;;
    -*)
      die "unknown option: $1"
      ;;
    *)
      break
      ;;
  esac
done

[ "$#" -ge 3 ] || {
  usage
  exit 1
}

output_file="$1"
shift
input_files=("$@")

require_command ffmpeg
require_command ffprobe

for input_file in "${input_files[@]}"; do
  [ -f "$input_file" ] || die "input file not found: $input_file"
  has_stream "$input_file" v:0 || die "missing video stream: $input_file"
done

baseline_video="$(video_signature "${input_files[0]}")"
baseline_audio="$(audio_signature "${input_files[0]}")"
[ -n "$baseline_video" ] || die "failed to read video signature from ${input_files[0]}"

for input_file in "${input_files[@]:1}"; do
  current_video="$(video_signature "$input_file")"
  current_audio="$(audio_signature "$input_file")"
  [ "$current_video" = "$baseline_video" ] || die "video streams are not concat-compatible: $input_file"
  [ "$current_audio" = "$baseline_audio" ] || die "audio streams are not concat-compatible: $input_file"
done

if [ "$dry_run" -eq 1 ]; then
  cat <<EOF
output_file=$output_file
video_signature=$baseline_video
audio_signature=$baseline_audio
inputs=${input_files[*]}
EOF
  exit 0
fi

ensure_parent_dir "$output_file"

faststart_args=()
case "$(normalized_extension "$output_file")" in
  mp4|m4v|mov)
    faststart_args=(-movflags +faststart)
    ;;
esac

list_file="$(mktemp)"
trap 'rm -f "$list_file"' EXIT

for input_file in "${input_files[@]}"; do
  printf "file '%s'\n" "$(concat_list_path "$input_file")" >>"$list_file"
done

ffmpeg \
  -y \
  -f concat \
  -safe 0 \
  -i "$list_file" \
  -c copy \
  "${faststart_args[@]}" \
  "$output_file"
