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

use warnings;
use strict;
use 5.010000;

use Exporter qw( import );
our @EXPORT_OK = qw( read_history_files channel_history_menu add_channel_to_history write_channel_history_to_file );

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

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



sub read_history_files {
    my ( $opt ) = @_;
    $opt->{channel_sticky}  = {};
    $opt->{channel_history} = {};
    if ( $opt->{max_channels} ) {
        if ( -e $opt->{s_channel_file} ) {
            $opt->{channel_sticky} = read_json( $opt->{s_channel_file} );
        }
        if ( -e $opt->{h_channel_file} ) {
            $opt->{channel_history} = read_json( $opt->{h_channel_file} );
        }
    }
}


sub channel_history_menu {
    my ( $opt ) = @_;
    my $list_size_idx = $opt->{list_size_idx};

    MENU : while ( 1 ) {
        my @list_size = ( '  ALL', '  50' );
        my $list_size_regexp = join '|', map { quotemeta } @list_size;
        my ( $channel, $sticky ) = ( '- Channel', '  Sticky' );
        # Choose
        my $choice = choose(
            [ undef, $channel, $sticky, $list_size[$list_size_idx] ],
            { prompt => 'Choose:', layout => 3, undef => '  QUIT' }
        );
        if ( ! defined $choice ) {
            exit;
        }
        elsif ( $choice eq $channel ) {
            my ( $sticky,  $sticky_url )  = _sticky_name_and_url( $opt->{channel_sticky} );
            my ( $history, $history_url, $last ) = _history_name_and_url( $opt, $opt->{channel_history} );
            my $prompt = 'Channels:' . "\n";
            my @ids;

            CHANNEL: while ( 1 ) {
                my $confirm = '  CONFIRM';
                my @pre = ( undef, $confirm );
                my $choices = _channel_choices( \@pre, $sticky, $history, $last );
                # Choose
                my @indexes = choose(
                    $choices,
                    { prompt => $prompt . "\nYour choice:", layout => 3, index => 1,
                        undef => '  BACK', no_spacebar => [ 0 .. $#pre, $#$choices ] }
                );
                if ( ! $indexes[0] ) {
                    if ( @ids ) {
                        $prompt = 'Channels:' . "\n";
                        @ids = ();
                        next CHANNEL;
                    }
                    else {
                        next MENU;
                    }
                }
                if ( $choices->[$indexes[0]] eq $confirm ) {
                    shift @indexes;
                    for my $i ( @indexes ) {
                        $i -= @pre;
                        if ( $i <= $#$sticky ) {
                            push @ids, $sticky_url->[$i];
                            $prompt .= sprintf "= %s (%s)\n", $sticky->[$i], $opt->{channel_sticky}{$sticky_url->[$i]}{channel_id};
                        }
                        else {
                            $i -= @$sticky;
                            push @ids, $history_url->[$i];
                            $prompt .= sprintf "= %s (%s)\n", $history->[$i], $opt->{channel_history}{$history_url->[$i]}{channel_id};
                        }
                    }
                    $opt->{nr_of_latest_videos} = $list_size[$list_size_idx] =~ /\D(\d+)/ ? $1 : 0;
                    return @ids;
                }
                else {
                    for my $i ( @indexes ) {
                        $i -= @pre;
                        if ( $i <= $#$sticky ) {
                            push @ids, $sticky_url->[$i];
                            $prompt .= sprintf "= %s (%s)\n", $sticky->[$i], $opt->{channel_sticky}{$sticky_url->[$i]}{channel_id};
                        }
                        else {
                            $i -= @$sticky;
                            push @ids, $history_url->[$i];
                            $prompt .= sprintf "= %s (%s)\n", $history->[$i], $opt->{channel_history}{$history_url->[$i]}{channel_id};
                        }
                    }
                }
            }
        }
        elsif ( $choice eq $sticky ) {
            my ( $sticky,  $sticky_url )  = _sticky_name_and_url( $opt->{channel_sticky} );
            my ( $history, $history_url ) = _history_name_and_url( $opt, $opt->{channel_history} );
            my $changed = 0;
            STICKY: while ( 1 ) {
                my @pre = ( undef );
                my $idx = choose(
                    [ @pre, map( "+ $_", @$sticky ), map( "- $_", @$history ) ],
                    { prompt => 'Choose:', layout => 3, index => 1, undef => '  <<' }
                );
                if ( ! $idx ) {
                    if ( $changed ) {
                        write_json( $opt->{s_channel_file}, $opt->{channel_sticky} );
                        write_json( $opt->{h_channel_file}, $opt->{channel_history} );
                    }
                    next MENU;
                }
                else {
                    $changed++;
                    $idx-= @pre;
                    if ( $idx > $#$sticky ) {
                        $idx -= @$sticky;
                        my $channel_url = $history_url->[$idx];
                        $opt->{channel_sticky}{$channel_url} = delete $opt->{channel_history}{$channel_url};
                    }
                    else {
                        my $channel_url = $sticky_url->[$idx];
                        $opt->{channel_history}{$channel_url} = delete $opt->{channel_sticky}{$channel_url};
                        $opt->{channel_history}{$channel_url}{timestamp} = time();
                    }
                    ( $sticky,  $sticky_url )  = _sticky_name_and_url( $opt->{channel_sticky} );
                    ( $history, $history_url ) = _history_name_and_url( $opt, $opt->{channel_history} );
                }
            }
        }
        if ( $choice =~ /^$list_size_regexp\z/ ) {
            $list_size_idx++;
            $list_size_idx = 0 if $list_size_idx > $#list_size;
            next MENU;
        }
    }
}


sub _channel_choices {
    my ( $pre, $sticky, $history, $last ) = @_;
    my $choices = [ @$pre, map( "* $_", @$sticky ) ];
    for my $i ( 0 .. $#$history ) {
            push @$choices, "  $history->[$i]" if ! $last->[$i];
            push @$choices, "| $history->[$i]" if   $last->[$i];
    }
    return $choices;
}


sub _history_name_and_url {
    my ( $opt, $ref ) = @_;
    my $tmp_name = [];
    my $tmp_url  = [];
    my $tmp_last = [];
    my $count = 0;
    for my $key ( sort { $ref->{$b}{timestamp} <=> $ref->{$a}{timestamp} } keys %$ref ) {
        $count++;
        push @$tmp_name, $ref->{$key}{channel};
        push @$tmp_url, $key;
        push @$tmp_last, $count >= $opt->{max_channels} ? 1 : 0;
    }
    my $history_name = [];
    my $history_url  = [];
    my $history_last = [];
    if ( ! $opt->{channel_by_timestamp} ) {
        for my $i ( sort { lc $tmp_name->[$a] cmp lc $tmp_name->[$b] } 0 .. $#$tmp_name ) {
            push @$history_name, $tmp_name->[$i];
            push @$history_url,  $tmp_url->[$i];
            push @$history_last, $tmp_last->[$i];
        }
    }
    else {
        $history_name = $tmp_name;
        $history_url  = $tmp_url;
        $history_last = $tmp_last;
    }
    return $history_name, $history_url, $history_last;
}


sub _sticky_name_and_url {
    my ( $ref ) = @_;
    my $sticky_name = [];
    my $sticky_url  = [];
    for my $key ( sort { lc $ref->{$a}{channel} cmp lc $ref->{$b}{channel} } keys %$ref ) {
        push @$sticky_name, $ref->{$key}{channel};
        push @$sticky_url, $key;
    }
    return $sticky_name, $sticky_url;
}


sub add_channel_to_history {
    my ( $opt, $info, $video_id ) = @_;
    my $channel       = $info->{$video_id}{uploader};
    my $channel_id    = $info->{$video_id}{uploader_id};
    my $extractor_key = $info->{$video_id}{extractor_key};
    my $channel_url;
    $channel_url = 'c#'                if $info->{$video_id}{extractor_key} eq 'Youtube';
    $channel_url = 'http://vimeo.com/' if $info->{$video_id}{extractor_key} eq 'Vimeo';
    if ( defined $channel_url ) {
        $channel_url .= $channel_id;
        if ( none{ $channel_url eq $_ } keys %{$opt->{channel_sticky}} ) {
            $opt->{channel_history}{$channel_url} = {
                channel_url   => $channel_url,
                channel       => $channel,
                channel_id    => $channel_id,
                extractor_key => $extractor_key,
                timestamp     => time(),
            };
        }
    }
}


sub write_channel_history_to_file {
    my ( $opt ) = @_;
    my $c_hist = $opt->{channel_history};
    my @keys = sort { $c_hist->{$b}{timestamp} <=> $c_hist->{$a}{timestamp} } keys %$c_hist;
    while ( @keys > $opt->{max_channels} ) {
        my $key = pop @keys;
        delete $c_hist->{$key};
        @keys = sort { $c_hist->{$b}{timestamp} <=> $c_hist->{$a}{timestamp} } keys %$c_hist;
    }
    write_json( $opt->{h_channel_file}, $c_hist );
}


1;


__END__
