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::ChooseVideos;

use warnings;
use strict;
use 5.010000;

use Exporter qw( import );
our @EXPORT_OK = qw( choose_videos set_sort_videolist );

use Encode qw( decode );

use Encode::Locale  qw();
use List::MoreUtils qw( any none );
use Term::Choose    qw( choose );
use Term::Form      qw();

use App::YTDL::Helper qw( check_mapping_stdout );



sub _my_sort {
    my ( $sort_item, $sort_order, $h_ref, $a, $b ) = @_;
    my @s = $sort_order eq 'Asc'
                ? ( $h_ref->{$a}{$sort_item}, $h_ref->{$b}{$sort_item} )
                : ( $h_ref->{$b}{$sort_item}, $h_ref->{$a}{$sort_item} );
    if ( $sort_item eq 'view_count_raw' || $sort_item eq 'date_sort' ) {
       $s[0] <=> $s[1] || $h_ref->{$a}{title} cmp $h_ref->{$b}{title};
    }
    else {
       $s[0] cmp $s[1] || $h_ref->{$a}{title} cmp $h_ref->{$b}{title};
   }
}


sub choose_videos {
    my ( $opt, $info, $tmp, $ex, $prompt ) = @_;
    my $length_view_count  = 0;
    my $length_video_id    = 0;
    my $length_upload_date = 0;
    my $has_date_sort      = 0;
    my $has_view_count     = 0;
    my $has_duration       = 0;
    for my $video_id ( keys %{$tmp->{$ex}} ) {
        $has_duration++   if $tmp->{$ex}{$video_id}{duration} ne '-:--:--';
        $has_date_sort++  if $tmp->{$ex}{$video_id}{date_sort};
        $has_view_count++ if $tmp->{$ex}{$video_id}{view_count};
        $length_video_id    = length $video_id                           if length $video_id > $length_video_id;
        $length_view_count  = length $tmp->{$ex}{$video_id}{view_count}  if length $tmp->{$ex}{$video_id}{view_count} > $length_view_count;
        $length_upload_date = length $tmp->{$ex}{$video_id}{upload_date} if length $tmp->{$ex}{$video_id}{upload_date} > $length_upload_date;
    }
    if ( $length_upload_date && $length_upload_date < 10 ) {
        $length_upload_date = 10;
    }
    my $regexp;
    my $back   = sprintf "%*s", $length_video_id, '   BACK';
    my $filter = sprintf "%*s", $length_video_id, ' FILTER';
    my $sort   = sprintf "%*s", $length_video_id, '   SORT';
    my $enter  = sprintf "%*s", $length_video_id, '  ENTER';
    my %chosen_video_ids;
    my @last_chosen_video_ids = ();

    FILTER: while ( 1 ) {
        my @pre  = ( length $regexp ? ( undef, $enter ) : ( undef, $filter, $sort, $enter ) );
        my @videos;
        my @tmp_video_ids;
        my $index = $#pre;
        my $mark = [];
        my $sort_item  = $opt->{list_sort_item};
        my $sort_order = $opt->{list_sort_order};
        if ( $sort_item eq 'view_count_raw' && ! $has_view_count ) {
            $sort_item = 'upload_date';
        }
        if ( $sort_item eq 'duration' && ! $has_duration ) {
            $sort_item = 'upload_date';
        }
        if ( $sort_item eq 'upload_date' ) {
            if ( ! $length_upload_date ) {
                $sort_item = 'title';
                $sort_order = 'Asc';
            }
            elsif ( $has_date_sort ) {
                $sort_item = 'date_sort';
                $sort_order = $sort_order eq 'Asc' ? 'Desc' : 'Asc';
            }
        }
        my @video_ids = sort { _my_sort( $sort_item, $sort_order, $tmp->{$ex}, $a, $b ) }  keys %{$tmp->{$ex}};

        VIDEO_ID: for my $video_id ( @video_ids ) {
            my $title = $tmp->{$ex}{$video_id}{title};
            $title =~ s/\s+/ /g;
            $title =~ s/^\s+|\s+\z//g;
            if ( length $regexp ) {
                if ( $regexp =~ /^!~\s(.+)\z/ ) {
                    my $r = $1;
                    next VIDEO_ID if $title =~ /$r/i;
                }
                else {
                    next VIDEO_ID if $title !~ /$regexp/i;
                }
            }
            $tmp->{$ex}{$video_id}{from_list} = 1;
            if ( $ex eq 'youtube' ) {
                $tmp->{$ex}{$video_id}{extractor} = 'youtube';
            }
            $title = check_mapping_stdout( $opt, $title ) if $Encode::Locale::ENCODING_CONSOLE_OUT !~ /^UTF-/i;
            my $line = sprintf "%*s |", $length_video_id, $video_id;
            $line .= sprintf " %7s", $tmp->{$ex}{$video_id}{duration}                          if $has_duration;
            $line .= sprintf "  %*s", $length_upload_date, $tmp->{$ex}{$video_id}{upload_date} if $length_upload_date;
            if ( ( $opt->{list_sort_item} eq 'view_count_raw' || $opt->{show_view_count} ) && $has_view_count ) {
                $line .= sprintf "  %*s", $length_view_count, $tmp->{$ex}{$video_id}{view_count};
            }
            $line .= sprintf "  %s", $title;
            push @videos, $line;
            push @tmp_video_ids, $video_id;
            $index++;
            push @$mark, $index if any { $video_id eq $_ } keys %chosen_video_ids;
        }
        my $choices = [ @pre, @videos ];
        # Choose
        my @idx = choose(
            $choices,
            { prompt => $prompt . ':', layout => 3, index => 1, clear_screen => 1, mark => $mark,
              undef => $back, no_spacebar => [ 0 .. $#pre ] }
        );
        if ( ! defined $idx[0] || ! defined $choices->[$idx[0]] ) {
            if ( length $regexp ) {
                delete @{$info->{$ex}}{ @last_chosen_video_ids };
                $regexp = '';
                next FILTER;
            }
            delete @{$info->{$ex}}{ keys %chosen_video_ids };
            return;
        }
        my $choice = $choices->[$idx[0]];
        if ( $choice eq $filter ) {
            shift @idx;
            @last_chosen_video_ids = ();
            for my $i ( @idx ) {
                my $video_id = $tmp_video_ids[$i - @pre];
                $info->{$ex}{$video_id} = $tmp->{$ex}{$video_id};
                $chosen_video_ids{$video_id}++;
                push @last_chosen_video_ids, $video_id;
            }
            for my $m ( @$mark ) {
                if ( none { $m == $_ } @idx ) {
                    my $video_id = $tmp_video_ids[$m - @pre];
                    delete $chosen_video_ids{$video_id};
                    delete $info->{$ex}{$video_id};
                }
            }
            my $trs = Term::Form->new();
            $regexp = $trs->readline( "Regexp: " );
            next FILTER;
        }
        elsif ( $choice eq $sort ) {
            set_sort_videolist( $opt );
        }
        else {
            if ( $choice eq $enter ) {
                shift @idx;
            }
            @last_chosen_video_ids = ();
            for my $i ( @idx ) {
                my $video_id = $tmp_video_ids[$i - @pre];
                $info->{$ex}{$video_id} = $tmp->{$ex}{$video_id};
                $chosen_video_ids{$video_id}++;
                push @last_chosen_video_ids, $video_id;
            }
            for my $m ( @$mark ) {
                if ( none { $m == $_ } @idx ) {
                    my $video_id = $tmp_video_ids[$m - @pre];
                    delete $chosen_video_ids{$video_id};
                    delete $info->{$ex}{$video_id};
                }
            }
            if ( length $regexp ) {
                $regexp = '';
                next FILTER;
            }
            else {
                return;
            }
        }
    }
}


sub set_sort_videolist {
    my ( $opt ) = @_;
    my $backup_item  = $opt->{list_sort_item};
    my $backup_order = $opt->{list_sort_order};
    my $sort_items = [ 'upload_date', 'title', 'view_count_raw', 'duration' ];
    my $confirm = '  CONFIRM';
    my @pre = ( undef, $confirm );
    my $choices = [ @pre, map { my $s = $_; $s =~ s/_raw\z//; $s =~ s/_/ /g; '- ' . $s } @$sort_items ];

    ITEM: while ( 1 ) {
        my $current = $opt->{list_sort_item};
        $current =~ s/_raw\z//;
        $current =~ s/_/ /g;
        my $prompt = sprintf 'Sort item: [%s]', $current;
        my $idx = choose (
            $choices,
            { prompt => $prompt, clear_screen => 0, layout => 3, index => 1, undef => '  BACK' }
        );
        if ( ! defined $idx || ! defined $choices->[$idx] ) {
            $opt->{list_sort_item} = $backup_item;
            return;
        }
        if ( $choices->[$idx] eq $confirm ) {
            last ITEM;
        }
        $idx -= @pre;
        $opt->{list_sort_item} = $sort_items->[$idx];
    }

    ORDER: while ( 1 ) {
        my $curr_sort_item = $opt->{list_sort_item};
        $curr_sort_item =~ s/_raw\z//;
        $curr_sort_item =~ s/_/ /g;
        my $order_prompt = sprintf 'Sort order "%s": [%s]', $curr_sort_item, $opt->{list_sort_order};
        my $choice = choose (
            [ @pre, '- Asc', '- Desc' ],
            { prompt => $order_prompt, clear_screen => 0, layout => 3, undef => '  BACK' }
        );
        if ( ! defined $choice ) {
            $opt->{list_sort_order} = $backup_order;
            return;
        }
        if ( $choice eq $confirm ) {
            $opt->{change}++;
            return;
        }
        $choice =~ s/^-\s//;
        $opt->{list_sort_order} = $choice;
    }
}


1;


__END__