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

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

usage() {
  cat <<'EOF'
Usage:
  trim-clip.sh [--dry-run] [--mode copy|accurate] <input> <start> <end|+duration> <output>

Examples:
  trim-clip.sh clip.mp4 00:10 00:22 out.mp4
  trim-clip.sh --mode accurate clip.mp4 00:10 +12 out.mp4

Environment:
  CRF            Video quality for accurate mode. Default: 18
  AUDIO_BITRATE  Audio bitrate for accurate mode. Default: 192k
EOF
}

dry_run=0
mode="copy"

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
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    --)
      shift
      break
      ;;
    -*)
      die "unknown option: $1"
      ;;
    *)
      break
      ;;
  esac
done

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

case "$mode" in
  copy|accurate)
    ;;
  *)
    die "--mode must be copy or accurate"
    ;;
esac

input_file="$1"
start_arg="$2"
end_or_duration_arg="$3"
output_file="$4"
crf="${CRF:-18}"
audio_bitrate="${AUDIO_BITRATE:-192k}"

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

require_command awk
require_command ffmpeg
require_command ffprobe

start_seconds="$(timestamp_to_seconds "$start_arg")"

case "$end_or_duration_arg" in
  +*)
    duration_seconds="$(timestamp_to_seconds "${end_or_duration_arg#+}")"
    end_seconds="$(math "$start_seconds + $duration_seconds")"
    ;;
  *)
    end_seconds="$(timestamp_to_seconds "$end_or_duration_arg")"
    duration_seconds="$(math "$end_seconds - $start_seconds")"
    ;;
esac

awk -v d="$duration_seconds" 'BEGIN { exit !(d > 0) }' || die "clip duration must be positive"

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

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

if [ "$dry_run" -eq 1 ]; then
  cat <<EOF
mode=$mode
input_file=$input_file
start_seconds=$start_seconds
end_seconds=$end_seconds
duration_seconds=$duration_seconds
has_audio=$has_audio
output_file=$output_file
EOF
  exit 0
fi

ensure_parent_dir "$output_file"

if [ "$mode" = "copy" ]; then
  ffmpeg \
    -y \
    -ss "$start_seconds" \
    -i "$input_file" \
    -map 0 \
    -c copy \
    -copyinkf \
    -avoid_negative_ts make_zero \
    "${faststart_args[@]}" \
    -t "$duration_seconds" \
    "$output_file"
elif [ "$has_audio" -eq 1 ]; then
  ffmpeg \
    -y \
    -i "$input_file" \
    -filter_complex "\
      [0:v:0]trim=start=${start_seconds}:end=${end_seconds},setpts=PTS-STARTPTS[v]; \
      [0:a:0]atrim=start=${start_seconds}:end=${end_seconds},asetpts=PTS-STARTPTS[a]" \
    -map "[v]" \
    -map "[a]" \
    -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 "trim=start=${start_seconds}:end=${end_seconds},setpts=PTS-STARTPTS" \
    -map 0:v:0 \
    -c:v libx264 \
    -crf "$crf" \
    -pix_fmt yuv420p \
    "${faststart_args[@]}" \
    "$output_file"
fi
