#!/usr/bin/env bash
# encode_videos.sh
[ -z "$BASH_VERSION" ] && exec bash "$0" "$@"
#
# Package downloaded MP4 files into HLS segments.
# Strategy:
#   1. Try stream copy (-c copy) — fast, lossless.
#   2. Check average segment duration. If > 7s the source has long keyframe
#      intervals (GOP ~10s) that cause HLS repeat stutter on players.
#      In that case, re-encode with forced keyframes every 6s and redo.
# Skips any video that already has a .encoded marker.
#
# Dependencies: ffmpeg, ffprobe, jq, python3
#
# Usage:   ./encode_videos.sh [videos_dir] [hls_dir]
# Defaults:
#   videos_dir -> BASE_DIR/videos
#   hls_dir    -> BASE_DIR/live/hls
#
# Output per video:
#   hls/{playlist}/{videoId}/index.m3u8
#   hls/{playlist}/{videoId}/seg*.ts
#   hls/{playlist}/{videoId}/segments.json

SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
BASE_DIR="$(dirname "$SCRIPT_DIR")"

VIDEOS_DIR="${1:-$BASE_DIR/videos}"
HLS_DIR="${2:-$BASE_DIR/live/hls}"

for cmd in ffmpeg ffprobe jq; do
    if ! command -v "$cmd" &>/dev/null; then
        echo "$cmd not found in PATH" >&2
        exit 1
    fi
done

mkdir -p "$HLS_DIR"

encoded=0
skipped=0
failed=0

for src in "$VIDEOS_DIR"/*/*.mp4; do
    [ -f "$src" ] || continue

    playlist="$(basename "$(dirname "$src")")"
    filename="$(basename "$src" .mp4)"
    out_dir="$HLS_DIR/$playlist/$filename"
    done_marker="$out_dir/.encoded"

    if [ -f "$done_marker" ]; then
        skipped=$((skipped + 1))
        continue
    fi

    echo "Encoding: $playlist/$filename"
    mkdir -p "$out_dir"

    ffmpeg -y -i "$src" \
        -c copy \
        -f hls \
        -hls_time 6 \
        -hls_playlist_type vod \
        -hls_flags independent_segments \
        -hls_segment_type mpegts \
        -hls_segment_filename "$out_dir/seg%05d.ts" \
        "$out_dir/index.m3u8" \
        2>"$out_dir/ffmpeg.log"

    if [ $? -ne 0 ]; then
        echo "  ERROR: encoding failed for $filename — see $out_dir/ffmpeg.log" >&2
        failed=$((failed + 1))
        continue
    fi

    # Check 1: average segment duration. If > 7s the source has long keyframe
    # intervals — re-encode with forced keyframes every 6s.
    avg_dur=$(awk '/^#EXTINF:/{sub(/^#EXTINF:/,"");sub(/,$/,"");sum+=$1;n++}END{if(n>0)printf "%.2f",sum/n;else print "0"}' "$out_dir/index.m3u8")
    needs_reencode=$(python3 -c "print(1 if float('${avg_dur:-0}') > 7.0 else 0)" 2>/dev/null)

    # Check 2: seg00000.ts must start with an IDR (keyframe) so that after a
    # HLS DISCONTINUITY the decoder can immediately render the new video.
    # A non-IDR first frame causes the player to freeze on the previous video
    # until the next IDR arrives (can be up to one full GOP = ~60s).
    if [ "${needs_reencode}" != "1" ] && [ -f "$out_dir/seg00000.ts" ]; then
        first_flag=$(ffprobe -select_streams v:0 \
            -show_entries packet=flags -of csv=p=0 -v quiet \
            "$out_dir/seg00000.ts" 2>/dev/null | head -1 | tr -d '\r\n')
        if [[ "$first_flag" != K* ]]; then
            echo "  seg00000.ts does not start with IDR (flags=${first_flag}) — re-encoding"
            needs_reencode=1
        fi
    fi

    if [ "${needs_reencode}" = "1" ]; then
        echo "  avg segment ${avg_dur}s > 7s or missing IDR — re-encoding with forced keyframes"
        rm -f "$out_dir"/seg*.ts "$out_dir/index.m3u8"
        ffmpeg -y -i "$src" \
            -c:v libx264 -preset fast -crf 23 \
            -force_key_frames "expr:gte(t,n_forced*6)" \
            -sc_threshold 0 \
            -c:a aac -b:a 128k \
            -f hls \
            -hls_time 6 \
            -hls_playlist_type vod \
            -hls_flags independent_segments \
            -hls_segment_type mpegts \
            -hls_segment_filename "$out_dir/seg%05d.ts" \
            "$out_dir/index.m3u8" \
            2>"$out_dir/ffmpeg.log"
        if [ $? -ne 0 ]; then
            echo "  ERROR: re-encode failed for $filename — see $out_dir/ffmpeg.log" >&2
            failed=$((failed + 1))
            continue
        fi
        echo "  re-encode done"
    fi

    duration_sec=$(ffprobe -v error -select_streams v:0 \
        -show_entries format=duration -of csv=p=0 "$src" 2>/dev/null)

    segments_json=$(awk '
        /^#EXTINF:/ {
            sub(/^#EXTINF:/, ""); sub(/,$/, ""); dur=$0
            getline uri
            printf "{\"index\":%d,\"uri\":\"/live/hls/%s/%s/%s\",\"duration\":%s},\n",
                idx++, pl, vid, uri, dur
        }
    ' idx=0 pl="$playlist" vid="$filename" "$out_dir/index.m3u8" \
    | sed '$ s/,$//')

    jq -n \
        --arg videoId     "$filename" \
        --arg playlist    "$playlist" \
        --arg durationSec "${duration_sec:-0}" \
        --argjson segments "[${segments_json:-}]" \
        '{
            videoId:     $videoId,
            playlist:    $playlist,
            durationSec: ($durationSec | tonumber | floor),
            hlsPath:     ("/live/hls/" + $playlist + "/" + $videoId + "/index.m3u8"),
            segments:    $segments
        }' > "$out_dir/segments.json"

    touch "$done_marker"
    encoded=$((encoded + 1))
    echo "  done -> $out_dir"
done

echo "Encoding complete: $encoded encoded, $skipped skipped, $failed failed."
[ $failed -gt 0 ] && exit 1
exit 0
