#!/usr/bin/env bash

declare -rA presets=(
    [davinci-resolve]="-c:v dnxhd -profile:v dnxhr_hq -pix_fmt yuv422p -c:a pcm_s16le"
    [instagram]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)':flags=lanczos -r 30 -c:v libx264 -profile:v high -level 4.1 -pix_fmt yuv420p -preset slow -crf 18 -bf 2 -g 15 -keyint_min 15 -x264-params \"open-gop=0:cabac=1:b-pyramid=none\" -movflags +faststart -c:a aac -b:a 96k"
    [insta-4k]="-r 30 -c:v libx264 -profile:v high -level 4.1 -pix_fmt yuv420p -preset slow -crf 18 -bf 2 -g 15 -keyint_min 15 -x264-params \"open-gop=0:cabac=1:b-pyramid=none\" -movflags +faststart -c:a aac -b:a 96k"
    [storage-hevc]="-c:v libx265 -preset slower -crf 18 -pix_fmt yuv420p10le -x265-params aq-mode=3:aq-strength=1.0:psy-rd=1.8:psy-rdoq=1.0 -c:a copy"
    [storage-av1]="-c:v libsvtav1 -preset 6 -crf 28 -pix_fmt yuv420p -g 240 -svtav1-params tune=0:aq-mode=2 -c:a copy"
    [storage-av1-1080p]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)' -c:v libsvtav1 -preset 6 -crf 28 -pix_fmt yuv420p -g 240 -svtav1-params tune=0:aq-mode=2 -c:a copy"
    [storage-av1-nvenc]="-c:v av1_nvenc -cq 28 -preset slow -pix_fmt yuv420p10le -c:a copy"
    [network]="-c:v libx264 -preset slow -crf 22 -pix_fmt yuv420p -c:a aac -b:a 128k"
    [network-1080p]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)' -c:v libx264 -preset slow -crf 22 -pix_fmt yuv420p -c:a aac -b:a 128k"
    [whatsapp]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)' -c:v libx264 -preset slow -crf 30 -profile:v baseline -level 3.0 -pix_fmt yuv420p -r 25 -g 50 -c:a aac -b:a 160k -r:a 44100"
)

declare -rA containers=(
    [davinci-resolve]="mov"
    [instagram]="mp4"
    [insta-4k]="mp4"
    [storage-hevc]="mkv"
    [storage-av1]="mkv"
    [storage-av1-1080p]="mkv"
    [storage-av1-nvenc]="mkv"
    [network]="mp4"
    [network-1080p]="mp4"
    [whatsapp]="mp4"
)

where="${1:-.}"
dest="${2:-$where}"

selection=$(find "$where" -type f | fzf --multi --preview 'ffprobe -v error -show_format -show_streams {}' --preview-window=up:wrap)

preset=$(
    printf '%s\n' "${!presets[@]}" | \
    fzf --multi --prompt "Select a preset"
)
flags="${presets[$preset]}"
container="${containers[$preset]}"

output_dir=$(find "$dest" -type d ! -name '.*' ! -path '*/.*/*' | fzf --preview 'tree -C {}' --preview-window=up:wrap --prompt "Select output directory: ")

if gum confirm "Flatten the directory structure?";
then
    flatten=true
else
    flatten=false
fi


function transcode_job {
    local ifile="$1"
    local output_dir="$2"
    local flatten="$3"
    local where="$4"
    local flags="$5"
    local container="$6"
    local fname=$(basename "$ifile")
    local segment=$(realpath --relative-to="$where" "$ifile")


    if [ "$flatten" = true ]; then
        output_file="$output_dir/$fname.$container"
    else
        output_file="$output_dir/$segment.$container"
    fi

    tmp_file=$(mktemp)

    echo "Running Command:  ffmpeg -y -i $ifile $flags $output_file" >> "$tmp_file"

    mkdir -p "$(dirname "$output_file")"

    if ffmpeg -y -i "$ifile" $(echo -n "$flags") "$output_file" 2>> "$tmp_file";
    then
        rm -f "$tmp_file"
    else
        # gum log "Failed to transcode $ifile. Check ./error.log for details."
        cat "$tmp_file" >> error.log
        rm -f "$tmp_file"

    fi
}
export -f transcode_job

mapfile -t files <<< "$selection"
len=${#files[@]}
i=1
for file in "${files[@]}"; do
    if [[ -f "$file" ]]; then
        gum spin --spinner dot --title "[$i/$len] Transcoding $file" -- bash -c "source <(declare -f transcode_job); transcode_job \"$file\" \"$output_dir\" \"$flatten\" \"$where\" \"$flags\" \"$container\""
    else
        echo "Skipping invalid file: $file" >&2
    fi
    ((i++))
done
