package # hide from PAUSE
App::YTDL::Info;

use warnings;
use strict;
use 5.010000;

use Exporter qw( import );
our @EXPORT_OK = qw( get_download_infos );

use File::Spec::Functions qw( catfile catdir );

use List::MoreUtils   qw( none first_index );
use Term::ANSIScreen  qw( :cursor :screen );
use Term::Choose      qw( choose );
use Unicode::GCString qw();

use if $^O eq 'MSWin32', 'Win32::Console::ANSI';

use App::YTDL::Info_Print qw( linefolded_print_info );
use App::YTDL::Helper     qw( term_size unicode_trim encode_stdout_lax encode_fs read_json write_json );
use App::YTDL::History    qw( add_channel_to_history write_channel_history_to_file );



sub get_download_infos {
    my ( $opt, $info ) = @_;
    my ( $cols, $rows ) = term_size();
    print "\n\n\n", '=' x $cols, "\n\n", "\n" x $rows;
    print locate( 1, 1 ), cldown;
    say 'Dir  : ', $opt->{video_dir};
    say 'Agent: ', $opt->{useragent} // '';
    print "\n";
    my @video_ids = sort {
           ( $info->{$b}{extractor_key} // '' ) cmp ( $info->{$a}{extractor_key} // '' )
        || ( $info->{$a}{playlist_id}   // '' ) cmp ( $info->{$b}{playlist_id}   // '' )
        || ( $info->{$a}{uploader_id}   // '' ) cmp ( $info->{$b}{uploader_id}   // '' )
        || ( $info->{$a}{upload_date}   // '' ) cmp ( $info->{$b}{upload_date}   // '' )
        || ( $info->{$a}{title}         // '' ) cmp ( $info->{$b}{title}         // '' )
    } keys %$info;
    my $fmt_aref;
    my $count = 0;
    $opt->{up} = 0;

    VIDEO: while ( @video_ids ) {
        my $video_id = shift @video_ids;
        $count++;
        my $key_len = 13;
        my $print_array = linefolded_print_info( $opt, $info, $video_id, $key_len );

        MENU: while ( 1 ) {
            print "\n";
            $opt->{up}++;
            binmode STDOUT, ':pop';
            print for map { encode_stdout_lax( $_ ) } @$print_array;
            binmode STDOUT, ':encoding(console_out)';
            $opt->{up} += @$print_array;
            print "\n";
            $opt->{up}++;
            $fmt_aref = _fmt_quality( $opt, $info, $fmt_aref, $video_id );
            if ( ! defined $fmt_aref ) {
                my ( $delete, $append, $pref_qualities, $quit ) = ( 'Delete', 'Append', 'Preferred qualities', 'Quit' );
                # Choose
                my $choice = choose(
                    [ undef, $quit, $delete, $append, $pref_qualities ],
                    { prompt => 'Your choice: ', undef => 'Back' }
                );
                if ( ! defined $choice ) {
                    print up( $opt->{up} ), cldown;
                    $opt->{up} = 0;
                    next MENU;
                }
                elsif ( $choice eq $quit ) {
                    print locate( 1, 1 ), cldown;
                    say "Quit";
                    exit;
                }
                elsif ( $choice eq $delete ) {
                    delete  $info->{$video_id};
                    if ( ! @video_ids ) {
                        print up( 2 ), cldown;
                        print "\n";
                    }
                    print up( $opt->{up} ), cldown;
                    $opt->{up} = 0;
                    $count--;
                    next VIDEO;
                }
                elsif ( $choice eq $append ) {
                    push @video_ids, $video_id;
                    print up( $opt->{up} ), cldown;
                    $opt->{up} = 0;
                    $count--;
                    next VIDEO;
                }
                elsif ( $choice eq $pref_qualities ) {
                    _set_preferred_qualities( $opt, $info, $video_id );
                    print up( $opt->{up} ), cldown;
                    $opt->{up} = 0;
                    next MENU;
                }
            }
            else {
                last MENU;
            }
        }
        print up( $opt->{up} ), cldown;
        $opt->{up} = 0;
        my $video_dir = $opt->{video_dir};
        if ( $opt->{extractor_dir} ) {
            if ( $info->{$video_id}{extractor_key} ) {
                my $extractor_dir = $info->{$video_id}{extractor_key};
                $extractor_dir =~ s/\s/_/g;
                $video_dir = catdir $video_dir, $extractor_dir;
                mkdir encode_fs( $video_dir ) or die $! if ! -d encode_fs( $video_dir );
            }
        }
        if ( $opt->{channel_dir} == 2 || $opt->{channel_dir} == 1 && $info->{$video_id}{from_list} ) {
            if ( $info->{$video_id}{uploader} ) {
                my $channel_name = $info->{$video_id}{uploader};
                $channel_name =~ s/\s/_/g;
                $video_dir = catdir $video_dir, $channel_name;
                mkdir encode_fs( $video_dir ) or die $! if ! -d encode_fs( $video_dir );
            }
        }
        printf "%*.*s : %s\n", $key_len, $key_len, 'video', $count;
        my $joined_fmts = join ' + ', @$fmt_aref;
        $print_array->[0] =~ s/\n\z//;
        $print_array->[0] .= " ($joined_fmts)\n";
        binmode STDOUT, ':pop';
        print for map { encode_stdout_lax( $_ ) } @$print_array;
        binmode STDOUT, ':encoding(console_out)';
        print "\n";
        for my $fmt ( @$fmt_aref ) {
            $info->{$video_id}{video_url}{$fmt} = $info->{$video_id}{fmt_to_info}{$fmt}{url};
            $info->{$video_id}{file_name}{$fmt} = catfile( $video_dir, _get_filename( $opt, $info, $video_id, $fmt ) );
            $info->{$video_id}{count} = $count;
            $opt->{total_nr_videos}++;

        }
        if ( $opt->{max_channels} && $info->{$video_id}{uploader_id} ) {
            add_channel_to_history( $opt, $info, $video_id );
        }
    }
    print "\n";
    if ( $opt->{max_channels} ) {
        write_channel_history_to_file( $opt );
    }
    if ( ! $opt->{total_nr_videos} ) {
        print locate( 1, 1 ), cldown;
        say "No videos";
        exit;
    }
    return $opt, $info;
}


sub _set_preferred_qualities {
    my ( $opt, $info, $video_id ) = @_;
    my $fmt_to_info = $info->{$video_id}{fmt_to_info};
    my $ex_key = $info->{$video_id}{extractor_key};
    my ( @qualities, @format_ids );
    if ( $ex_key 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->{preferred_file} );

    CHOICE: while ( 1 ) {
        my @pre = ( undef );
        my @choices = map {
            sprintf '%d. choice: %s', $_, join( ', ', map { $_ // '' } @{$pref_qual->{$ex_key}[$_-1]} )
        } 1 .. 3;
        my $idx_choice = choose(
            [ @pre, @choices ],
            { prompt => "Set preferred qualities ($ex_key):", layout => 3, index => 1, undef => '<<' }
        );
        if ( ! $idx_choice ) {
            write_json( $opt->{preferred_file}, $pref_qual );
            return;
        }
        $idx_choice -= @pre;
        @pre = ( undef );
        my $prompt = "Set preferred qualities ($ex_key):\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;
        }
        else {
            my @fmt_res_idx = map { $_ - @pre } @idx;
            my $fmt_aref = [ @format_ids[@fmt_res_idx] ];
            $pref_qual->{$ex_key}[$idx_choice] = $fmt_aref;
            next CHOICE;
        }
    }
}


sub _get_filename {
    my ( $opt, $info, $video_id, $fmt ) = @_;
    my $title  = $info->{$video_id}{title};
    my $suffix = $info->{$video_id}{fmt_to_info}{$fmt}{ext} // 'unknown';
    my $len_suffix = Unicode::GCString->new( $suffix )->columns();
    my $len_fmt    = Unicode::GCString->new( $fmt    )->columns();
    my $len_title  = $opt->{max_len_f_name} - ( $len_suffix + $len_fmt + 2 );
    my $file_name = unicode_trim( $title, $len_title );
    $file_name = $file_name . '_' . $fmt . '.' . $suffix;
    $file_name =~ s/^\s+|\s+\z//g;
    $file_name =~ s/\s/_/g;
    $file_name =~ s/^\.+//;
    #$file_name =~ s/[^\p{Word}.()]/-/g;
    $file_name =~ s/["\/\\:*?<>|]/-/g;
    # NTFS and FAT unsupported characters:  / \ : " * ? < > |
    return $file_name;
}


sub _fmt_quality {
    my ( $opt, $info, $fmt, $video_id ) = @_;
    my $auto_quality = $opt->{auto_quality};
    my $fmt_ok;
    if ( $auto_quality == 0 ) {
    }
    elsif ( $auto_quality == 1 && $info->{$video_id}{from_list} ) {
        my $list_id = $info->{$video_id}{playlist_id} // $info->{$video_id}{uploader_id};
        if ( $list_id ) {
            if ( ! defined $opt->{$list_id} ) {
                $fmt = _choose_fmt( $opt, $info, $video_id );
                return if ! defined $fmt;
                $opt->{$list_id} = $fmt;
            }
            else {
                $fmt = $opt->{$list_id};
            }
            $fmt_ok = 1;
        }
    }
    elsif ( $auto_quality == 2 && $info->{$video_id}{extractor_key} ) {
        my $pq_key = $info->{$video_id}{extractor_key};
        if ( ! defined $opt->{$pq_key} ) {
            $fmt = _choose_fmt( $opt, $info, $video_id );
            return if ! defined $fmt;
            $opt->{$pq_key} = $fmt;
        }
        else {
            $fmt = $opt->{ap_key};
        }
        $fmt_ok = 1;

    }
    elsif ( $auto_quality == 3 && $info->{$video_id}{extractor_key} ) {
        my $pref_qual = read_json( $opt->{preferred_file} );
        my @pref_qualities = @{$pref_qual->{$info->{$video_id}{extractor_key}}};
        PQ: for my $pq ( @pref_qualities ) {
            for my $q ( @$pq ) {
                $fmt_ok = 1;
                if ( none { $q eq $_ } keys %{$info->{$video_id}{fmt_to_info}} ) {
                    $fmt_ok = 0;
                    next PQ;
                }
            }
            $fmt = $pq;
            last PQ;
        }
        if ( ! $fmt_ok ) {
            print "\n";
            $opt->{up}++;
            say 'video_id: ' . $video_id .
                ! @pref_qualities
                ? ' - no preferred qualities found!'
                : ' - no matches between preferred fmts and available fmts!';
            $opt->{up}++;
        }
    }
    elsif ( $auto_quality == 4 && defined $info->{$video_id}{format_id} ) {
        $fmt = $info->{$video_id}{format_id};
        $fmt_ok = 1;
    }
    if ( ! $fmt_ok ) {
        $fmt = _choose_fmt( $opt, $info, $video_id );
        return if ! defined $fmt;
    }
    return $fmt;
}


sub _choose_fmt {
    my ( $opt, $info, $video_id ) = @_;
    my $fmt_to_info = $info->{$video_id}{fmt_to_info};
    my ( @choices, @format_ids );
    if ( $info->{$video_id}{extractor_key} 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_aref = [ @format_ids[@fmt_res_idx] ];
    return $fmt_aref;
}



1;


__END__
