The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package # hide from PAUSE
App::YTDL::SelectQuality;

use warnings;
use strict;
use 5.010000;

use Exporter qw( import );
our @EXPORT_OK = qw( set_preferred_qualities fmt_quality );

use List::MoreUtils qw( none );
use Term::Choose    qw( choose );

use App::YTDL::Helper qw( read_json write_json );



sub set_preferred_qualities {
    my ( $opt, $info, $ex, $video_id ) = @_;
    my $fmt_to_info = $info->{$ex}{$video_id}{fmt_to_info};
    my ( @qualities, @format_ids );
    if ( $ex eq 'youtube' ) {
        for my $fmt ( sort { $a <=> $b } keys %$fmt_to_info ) {
            if ( $fmt_to_info->{$fmt}{format} =~ /^\Q$fmt\E\s*-\s*(.+)\z/ ) {
                push @qualities, sprintf '%3s - %s %s', $fmt, $1, $fmt_to_info->{$fmt}{ext};
            }
            else {
                push @qualities, $fmt_to_info->{$fmt}{format} . ' ' . $fmt_to_info->{$fmt}{ext};
            }
            push @format_ids, $fmt;
        }
    }
    else {
        for my $fmt ( sort { $a cmp $b } keys %$fmt_to_info ) {
            push @qualities, $fmt_to_info->{$fmt}{format} . ' ' . $fmt_to_info->{$fmt}{ext};
            push @format_ids, $fmt;
        }
    }
    my $pref_qual = read_json( $opt, $opt->{preferred_file} ) // {};

    CHOICE: while ( 1 ) {
        my @pre = ( undef );
        my @choices = map {
            sprintf '%d. choice: %s', $_, join ', ', map( $_ // '', @{$pref_qual->{$ex}[$_-1]} )
        } 1 .. $opt->{pref_qual_slots};
        my $idx_choice = choose(
            [ @pre, @choices ],
            { prompt => "Set preferred qualities ($ex):", layout => 3, index => 1, undef => '<<' }
        );
        if ( ! $idx_choice ) {
            write_json( $opt, $opt->{preferred_file}, $pref_qual );
            return;
        }
        $idx_choice -= @pre;
        @pre = ( undef, 'RESET' );
        my $prompt = "Set preferred qualities ($ex):\n$choices[$idx_choice]";
        # Choose
        my @idx = choose(
            [ @pre, @qualities ],
            { prompt => $prompt, index => 1, order => 1, undef => '<<', no_spacebar => [ 0 .. $#pre ] }
        );
        if ( ! $idx[0] ) {
            next CHOICE;
        }
        elsif ( $idx[0] == 1 ) {
            $pref_qual->{$ex}[$idx_choice] = [];
            next CHOICE;
        }
        else {
            my @fmt_res_idx = map { $_ - @pre } @idx;
            my $fmt_list = [ @format_ids[@fmt_res_idx] ];
            $pref_qual->{$ex}[$idx_choice] = $fmt_list;
            next CHOICE;
        }
    }
}


sub fmt_quality {
    my ( $opt, $info, $fmt_list, $ex, $video_id ) = @_;
    my $auto_quality = $opt->{auto_quality};
    my $fmt_ok = 0;
    if ( $auto_quality eq 'keep_uploader_playlist' && $info->{$ex}{$video_id}{from_list} ) {
        my $list_id = $info->{$ex}{$video_id}{playlist_id};
        if ( ! length $list_id ) {
            $list_id = $info->{$ex}{$video_id}{uploader_id};
        }
        if ( length $list_id ) {
            if ( ! defined $opt->{$list_id} ) {
                $fmt_list = _choose_fmt( $opt, $info, $ex, $video_id );
                return if ! defined $fmt_list;
                $opt->{$list_id} = $fmt_list;
            }
            else {
                $fmt_list = $opt->{$list_id};
            }
            $fmt_ok = 1;
        }
    }
    elsif ( $auto_quality eq 'keep_extractor' ) {
        if ( ! defined $opt->{$ex} ) {
            $fmt_list = _choose_fmt( $opt, $info, $ex, $video_id );
            return if ! defined $fmt_list;
            $opt->{$ex} = $fmt_list;
        }
        else {
            $fmt_list = $opt->{$ex};
        }
        $fmt_ok = 1;

    }
    elsif ( $auto_quality eq 'preferred' ) {
        my $pref_qual = read_json( $opt, $opt->{preferred_file} ) // {};
        my @pref_qualities = @{$pref_qual->{$ex}//[]};
        PQ: for my $slot ( @pref_qualities ) {
            for my $fmt ( @$slot ) {
                $fmt_ok = 1;
                if ( none { $fmt eq $_ } keys %{$info->{$ex}{$video_id}{fmt_to_info}} ) {
                    $fmt_ok = 0;
                    next PQ;
                }
            }
            $fmt_list = $slot;
            last PQ;
        }
        if ( ! $fmt_ok ) {
            $fmt_list = [];
            print "\n";
            $opt->{up}++;
            printf "video_id %s - %s\n", $video_id, ! @pref_qualities
                ? 'no preferred qualities found!'
                : 'no matches between preferred fmts and available fmts!';
            $opt->{up}++;
        }
    }
    elsif ( $auto_quality eq 'default' && defined $info->{$ex}{$video_id}{format_id} ) {
        $fmt_list = [ split /\s*\+\s*/, $info->{$ex}{$video_id}{format_id} ];
        $fmt_ok = 1;
    }
    for my $fmt ( @$fmt_list ) {
        if ( none { $fmt eq $_ } keys %{$info->{$ex}{$video_id}{fmt_to_info}} ) {
            $fmt_ok = 0;
            last;
        }
    }
    if ( ! $fmt_ok ) {
        $fmt_list = _choose_fmt( $opt, $info, $ex, $video_id );
        return if ! defined $fmt_list;
    }
    return $fmt_list;
}


sub _choose_fmt {
    my ( $opt, $info, $ex, $video_id ) = @_;
    my $fmt_to_info = $info->{$ex}{$video_id}{fmt_to_info};
    my ( @choices, @format_ids );
    if ( $ex eq 'youtube' ) {
        for my $fmt ( sort { $a <=> $b } keys %$fmt_to_info ) {
            if ( $fmt_to_info->{$fmt}{format} =~ /^\Q$fmt\E\s*-\s*(.+)\z/ ) {
                push @choices, sprintf '%3s - %s %s', $fmt, $1, $fmt_to_info->{$fmt}{ext};
            }
            else {
                push @choices, $fmt_to_info->{$fmt}{format} . ' ' . $fmt_to_info->{$fmt}{ext};
            }
            push @format_ids, $fmt;
        }
    }
    else {
        for my $fmt ( sort { $a cmp $b } keys %$fmt_to_info ) {
            push @choices, $fmt_to_info->{$fmt}{format} . ' ' . $fmt_to_info->{$fmt}{ext};
            push @format_ids, $fmt;
        }
    }
    my @pre = ( undef );
    print "\n";
    $opt->{up}++;
    # Choose
    my @idx = choose(
        [ @pre, @choices ],
        { prompt => 'Your choice: ', index => 1, order => 1, undef => 'Menu', no_spacebar => [ 0 .. $#pre ] }
    );
    return if ! $idx[0];
    my @fmt_res_idx = map { $_ - @pre } @idx;
    my $fmt_list = [ @format_ids[@fmt_res_idx] ];
    return $fmt_list;
}



1;


__END__