#!/usr/bin/env raku

use Pod::To::Text;
use FFmpegProgressBar;
use FFmpegProgressBar::Parser;

sub ARGS-TO-CAPTURE(&main, @args --> Capture) {
    for @args -> $arg {
        return Capture.new(hash => { help    => True }) if $arg eq any('-h', '--help');
        return Capture.new(hash => { man     => True }) if $arg eq '--man';
        return Capture.new(hash => { version => True }) if $arg eq '--version';
    }
    return get-effective-options(@args).as-capture;
}

=begin pod

=head1 NAME

    ffpb - Run ffmpeg with a progress bar

=head1 SYNOPSIS

    ffpb [options] [ffmpeg options]

=head1 OPTIONS

=item B<-h>, B<--help>
Show this help message

=item B<-V>, B<--verbose>
Show detected duration and executed command

=item B<-Q>, B<--quiet>
Suppress progress bar rendering (useful when only using progress API)

=item B<-F>, B<--frames>
Show current frame and encoding fps

=item B<-B>, B<--bitrate>
Show output bitrate

=item B<-S>, B<--style>=I<style>
Set progress bar style (bar, hash, hash-dash, equals)

=item B<-D>, B<--duration>=I<seconds>
Set duration in seconds (skip auto-detection)

=item B<-M>, B<--ffmpeg>=I<path>
Path to ffmpeg binary

=item B<-P>, B<--ffprobe>=I<path>
Path to ffprobe binary

=item B<-E>, B<--stderr>[=I<N>|all]
Show ffmpeg stderr on successful completion. Without value: last 20 lines. With value: N lines or 'all'.

=item B<--version>
Show version information

=item B<--man>
Show full manual page

=head1 EXAMPLES

    # Basic encoding
        ffpb -i input.mp4 output.mkv

    # With verbose output
        ffpb -V -i input.mp4 output.mp4

    # With frames and bitrate                                   
        ffpb -F -B -i input.mp4 output.mp4

    # With custom bar style
        ffpb -S hash -i input.mp4 output.mp4

    # With duration override
        ffpb -D 60 -i input.mp4 output.mp4

    # With custom ffmpeg/ffprobe paths
        ffpb -M /usr/bin/ffmpeg -P /usr/bin/ffprobe -i input.mp4 output.mp4

    # Show stderr on success
        ffpb -E -i input.mp4 output.mp4

    # Last 50 lines
        ffpb -E 50 -i input.mp4 output.mp4

    # All stderr output      
        ffpb -E all -i input.mp4 output.mp4

    # Two-pass encoding (bitrate must be set for a meaningful second pass)
        ffpb -i input.mp4 -c:v libx264 -b:v 1M -pass 2 -f mp4 output.mp4

=head1 TWO-PASS ENCODING

FFmpegProgressBar automatically detects two-pass encoding when the C<-pass 2>
flag is used. It will run the analysis pass (pass 1) silently, then display
the progress bar for the encoding pass.

Example:

    ffpb -i input.mp4 -c:v libx264 -b:v 1M -pass 2 -f mp4 output.mp4

Ctrl+C during pass 1 will cleanly abort.

=head1 CONFIG FILES

Config files are checked in the following order:

=head2 Unix/Linux/macOS

=item F<~/.ffpbrc>

=item F<~/.config/ffpbrc>

=item F<~/.config/ffpb/config>

=item F</etc/ffpbrc>

=head2 Windows

=item F<%USERPROFILE%\.ffpbrc>

=item F<%USERPROFILE%\.config\ffpbrc>

=item F<%USERPROFILE%\.config\ffpb\config>

=item F<%APPDATA%\ffpb\config>

=item F<%APPDATA%\ffpbrc>

Each line should contain one option (like CLI arguments). Lines
starting with C<#> are treated as comments.

=head1 SIGNAL HANDLING

=item B<Unix/Linux/macOS>: Pressing 'q' or Ctrl+C cleanly stops encoding. First
Ctrl+C sends 'q' (graceful), second Ctrl+C force-kills ffmpeg, third Ctrl+C exits
the program entirely.

=item B<Windows>: Pressing 'q' provides graceful shutdown (recommended). Ctrl+C
force kills ffmpeg immediately due to limitations with how the native executable
wrapper handles console signals on Windows.

=head1 API
       
For full library API documentation, run: rakudoc FFmpegProgressBar

=head1 AUTHOR

Sasha Abbott <sashaa@disroot.org>

=head1 LICENSE

This library is free software; you can redistribute it and/or modify it under CC0.

=end pod

my $short-help = q:to/SHORT/;
ffpb - Run ffmpeg with a progress bar

SYNOPSIS
    ffpb [options] [ffmpeg options]

OPTIONS
  -h, --help      Show this help message
  -V, --verbose   Show detected duration and executed command
  -Q, --quiet     Suppress progress bar rendering
  -F, --frames    Show current frame and encoding fps
  -B, --bitrate   Show output bitrate
  -S, --style     Set progress bar style (bar, hash, hash-dash, equals)
  -D, --duration  Set duration in seconds (skip auto-detection)
  -M, --ffmpeg    Path to ffmpeg binary
  -P, --ffprobe   Path to ffprobe binary
  -E, --stderr    Show stderr on success (last 20 lines, or --stderr all)
  --version       Show version information
  --man           Show full manual page

See 'ffpb --man' for config file locations and full documentation.
SHORT

my $full-man = $=pod[0];

sub USAGE() {
    print $short-help;
}

multi MAIN(Bool :$help!) {
    print $short-help;
}

multi MAIN(Bool :$man!) {
    use Pod::To::Man;
    
    my $roff = Pod::To::Man.pod2man($full-man, :program('ffpb'));
    
    if $*DISTRO.is-win {
        my $text = pod2text($full-man);
        my $tmp = $*TMPDIR.child("ffpb-man-{$*PID}.txt");
        $tmp.spurt($text);
        my $proc = run('cmd', '/c', 'more', $tmp.Str);
        if $proc.exitcode != 0 {
            print $text;
        }
        LEAVE { try { $tmp.unlink } if $tmp.e };
    } else {
        # Unix: render to roff and display with man
        my $tmp = $*TMPDIR.child("ffpb-man-{$*PID}.1");
        LEAVE { $tmp.unlink if $tmp.e };
        $tmp.spurt($roff);
        run('man', $tmp);
    }
}

multi MAIN(Bool :$version!) {
    say "FFmpegProgressBar version " ~ version();
}

multi MAIN(
    Bool :$verbose = False,
    Bool :$quiet = False,
    Bool :$show-frames = False,
    Bool :$show-bitrate = False,
    Str :$bar-type = '',
    Numeric :$duration = 0,
    Str :$ffmpeg = '',
    Str :$ffprobe = '',
    Str :$stderr-lines = '',
    *@ffmpeg-args,
) {
    if !@ffmpeg-args {
        print $short-help;
        exit 0;
    }
    
    die "Duration must be >=0" if $duration < 0;
    
    exit FfmpegProgress.new(
        :verbose($verbose),
        :quiet($quiet),
        :show-frames($show-frames),
        :show-bitrate($show-bitrate),
        :bar-type($bar-type),
        :duration($duration),
        :ffmpeg($ffmpeg eq '' ?? 'ffmpeg' !! $ffmpeg),
        :ffprobe($ffprobe eq '' ?? 'ffprobe' !! $ffprobe),
        :stderr-lines($stderr-lines),
    ).run(@ffmpeg-args);
}
