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

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

usage() {
  cat <<'EOF'
Usage:
  transition-two-clips.sh [--dry-run] [--transition NAME] [--duration SECONDS] [--width N] [--height N] [--fps VALUE] <clip1> <clip2> <output>

Examples:
  transition-two-clips.sh clip1.mp4 clip2.mp4 out.mp4
  transition-two-clips.sh --transition fadewhite --duration 0.12 clip1.mp4 clip2.mp4 out.mp4
  transition-two-clips.sh --width 1080 --height 1920 --fps 30 clip1.mp4 clip2.mp4 out.mp4

Environment:
  CRF            Video quality. Default: 18
  AUDIO_BITRATE  Audio bitrate. Default: 192k
  SAMPLE_RATE    Audio sample rate. Default: 48000
EOF
}

dry_run=0
transition="fade"
duration="0.20"
width=""
height=""
fps=""
crf="${CRF:-18}"
audio_bitrate="${AUDIO_BITRATE:-192k}"
sample_rate="${SAMPLE_RATE:-48000}"

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

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

clip1="$1"
clip2="$2"
output_file="$3"

[ -f "$clip1" ] || die "clip not found: $clip1"
[ -f "$clip2" ] || die "clip not found: $clip2"
assert_positive_number "duration" "$duration"
assert_positive_number "CRF" "$crf"
assert_positive_number "SAMPLE_RATE" "$sample_rate"

require_command ffmpeg
require_command ffprobe

has_stream "$clip1" v:0 || die "missing video stream: $clip1"
has_stream "$clip2" v:0 || die "missing video stream: $clip2"
has_stream "$clip1" a:0 || die "missing audio stream: $clip1"
has_stream "$clip2" a:0 || die "missing audio stream: $clip2"

if [ -n "$width" ] || [ -n "$height" ]; then
  [ -n "$width" ] || die "set both --width and --height together"
  [ -n "$height" ] || die "set both --width and --height together"
else
  width="$(ffprobe_stream_field "$clip1" v:0 width)"
  height="$(ffprobe_stream_field "$clip1" v:0 height)"
fi

if [ -z "$fps" ]; then
  fps="$(ffprobe_stream_field "$clip1" v:0 r_frame_rate)"
fi
[ -n "$fps" ] || fps="30"

assert_positive_number "width" "$width"
assert_positive_number "height" "$height"

clip1_duration="$(ffprobe_format_field "$clip1" duration)"
[ -n "$clip1_duration" ] || die "failed to read duration from $clip1"
offset="$(math "$clip1_duration - $duration")"
awk -v o="$offset" 'BEGIN { exit !(o > 0) }' || die "transition duration must be shorter than the first clip duration"

if [ "$dry_run" -eq 1 ]; then
  cat <<EOF
transition=$transition
duration=$duration
clip1=$clip1
clip2=$clip2
width=$width
height=$height
fps=$fps
offset=$offset
output_file=$output_file
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

ffmpeg \
  -y \
  -i "$clip1" \
  -i "$clip2" \
  -filter_complex "\
    [0:v:0]scale=${width}:${height}:force_original_aspect_ratio=increase,crop=${width}:${height},fps=${fps},setsar=1,format=yuv420p[v0]; \
    [0:a:0]aformat=sample_rates=${sample_rate}:channel_layouts=stereo[a0]; \
    [1:v:0]scale=${width}:${height}:force_original_aspect_ratio=increase,crop=${width}:${height},fps=${fps},setsar=1,format=yuv420p[v1]; \
    [1:a:0]aformat=sample_rates=${sample_rate}:channel_layouts=stereo[a1]; \
    [v0][v1]xfade=transition=${transition}:duration=${duration}:offset=${offset}[vxf]; \
    [vxf]fillborders=left=2:right=2:top=0:bottom=0:mode=mirror[v]; \
    [a0][a1]acrossfade=d=${duration}:c1=tri:c2=tri[a]" \
  -map "[v]" \
  -map "[a]" \
  -c:v libx264 \
  -crf "$crf" \
  -pix_fmt yuv420p \
  -c:a aac \
  -b:a "$audio_bitrate" \
  "${faststart_args[@]}" \
  "$output_file"
