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

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

usage() {
  cat <<'EOF'
Usage:
  make-vertical.sh [--dry-run] [--mode crop|pad|dynamic] [--width N] [--height N] [--fps N] <input> <output>

Examples:
  make-vertical.sh source.mp4 vertical.mp4
  make-vertical.sh --mode dynamic source.mp4 vertical.mp4
  make-vertical.sh --mode pad --width 1080 --height 1920 source.mp4 vertical.mp4

Environment:
  CRF            Video quality. Default: 18
  AUDIO_BITRATE  Audio bitrate. Default: 192k
  X_DRIFT        Horizontal drift in pixels for dynamic mode. Default: 36
  DRIFT_SPEED    Sinusoidal drift speed for dynamic mode. Default: 0.9
  PAD_COLOR      Pad color for pad mode. Default: black
EOF
}

dry_run=0
mode="crop"
width="1080"
height="1920"
fps="30"
crf="${CRF:-18}"
audio_bitrate="${AUDIO_BITRATE:-192k}"
x_drift="${X_DRIFT:-36}"
drift_speed="${DRIFT_SPEED:-0.9}"
pad_color="${PAD_COLOR:-black}"

while [ "$#" -gt 0 ]; do
  case "$1" in
    --dry-run)
      dry_run=1
      shift
      ;;
    --mode)
      shift
      [ "$#" -gt 0 ] || die "missing value for --mode"
      mode="$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 2 ] || {
  usage
  exit 1
}

case "$mode" in
  crop|pad|dynamic)
    ;;
  *)
    die "--mode must be crop, pad, or dynamic"
    ;;
esac

input_file="$1"
output_file="$2"

[ -f "$input_file" ] || die "input file not found: $input_file"

assert_positive_number "width" "$width"
assert_positive_number "height" "$height"
assert_positive_number "fps" "$fps"
assert_positive_number "CRF" "$crf"
assert_non_negative_number "X_DRIFT" "$x_drift"
assert_positive_number "DRIFT_SPEED" "$drift_speed"

require_command ffmpeg
require_command ffprobe

has_audio=0
if has_stream "$input_file" a:0; then
  has_audio=1
fi

case "$mode" in
  crop)
    video_filter="scale=-2:${height},crop=${width}:${height},fps=${fps},setsar=1"
    ;;
  pad)
    video_filter="scale=${width}:-2,pad=${width}:${height}:(ow-iw)/2:(oh-ih)/2:${pad_color},fps=${fps},setsar=1"
    ;;
  dynamic)
    video_filter="scale=-2:${height},crop=${width}:${height}:x='min(max((iw-ow)/2+${x_drift}*sin(${drift_speed}*t)\\,0)\\,iw-ow)':y='(ih-oh)/2',fps=${fps},setsar=1"
    ;;
esac

if [ "$dry_run" -eq 1 ]; then
  cat <<EOF
mode=$mode
input_file=$input_file
width=$width
height=$height
fps=$fps
has_audio=$has_audio
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

if [ "$has_audio" -eq 1 ]; then
  ffmpeg \
    -y \
    -i "$input_file" \
    -vf "$video_filter" \
    -map 0:v:0 \
    -map 0:a:0 \
    -c:v libx264 \
    -crf "$crf" \
    -pix_fmt yuv420p \
    -c:a aac \
    -b:a "$audio_bitrate" \
    "${faststart_args[@]}" \
    "$output_file"
else
  ffmpeg \
    -y \
    -i "$input_file" \
    -vf "$video_filter" \
    -map 0:v:0 \
    -c:v libx264 \
    -crf "$crf" \
    -pix_fmt yuv420p \
    "${faststart_args[@]}" \
    "$output_file"
fi
