#!/usr/bin/env perl
# generate a SiteNews test file from RSS feeds of actual WebFetch releases on MetaCPAN

use strict;
use warnings;
use utf8;
use feature qw(say);
use autodie;
use Readonly;
use File::Temp;
use File::Basename qw(basename);
use Getopt::Long;
use Data::Dumper;
use DateTime::Format::ISO8601;

use WebFetch;
use WebFetch::RSS;

# configuration
Readonly::Scalar my $progname        => basename($0);
Readonly::Scalar my $release_cutoff  => "2000-01-01T00:00:00-00:00";    # only use WebFetch releases since 2000
Readonly::Scalar my $date_num        => 0;                              # field number for date from WebFetch::RSS
Readonly::Scalar my $title_num       => 1;                              # field number for title
Readonly::Scalar my $link_num        => 1;                              # field number for link
Readonly::Scalar my $creator_num     => 5;                              # field number for creator
Readonly::Scalar my $tmpdir_template => "WebFetch-XXXXXXXXXX";
Readonly::Hash my %sitenews_global => (
    categories => "release",
    url_prefix => "https://example.net/webfetch-releases/",
    locale     => "en-US",
    time_zone  => "America/Los Angeles",
);
Readonly::Array my @rss_urls => qw(
    https://metacpan.org/dist/WebFetch/releases.rss
    https://metacpan.org/dist/WebFetch-Input-Atom/releases.rss
    https://metacpan.org/dist/WebFetch-Input-RSS/releases.rss
    https://metacpan.org/dist/WebFetch-Output-TT/releases.rss
    https://metacpan.org/dist/WebFetch-Output-TWiki/releases.rss
);

# create WebFetch::Output::Capture to capture RSS files read by WebFetch
package WebFetch::Output::Capture;
use base 'WebFetch';
use Carp;
use Data::Dumper;
use Try::Tiny;

__PACKAGE__->module_register("output:capture");
my @news_items;
my $iso8601 = DateTime::Format::ISO8601->new();

# "capture" format handler
# specialized capture function for this script only picks WebFetch releases since 2000
sub fmt_handler_capture
{
    my ( $self, $filename ) = @_;

    WebFetch::debug "fetch: " . Dumper( $self->{data} );
    $self->no_savables_ok();    # rather than let WebFetch save the data, we'll take it here
    my $cutoff_dt = $iso8601->parse_datetime($release_cutoff);
    if ( exists $self->{data}{records} ) {
        push @news_items, grep { $iso8601->parse_datetime( $_->[$date_num] ) > $cutoff_dt } @{ $self->{data}{records} };
    }
    return 1;
}

# return the file list
sub news_items
{
    return @news_items;
}

# sort RSS items by date field
sub sort_items_revchron
{
    my ( $a_dt, $b_dt );
    if ( not defined $main::a->[$date_num] ) {
        Carp::confess( "sort_items_revchron: blank date (a): " . Dumper( $main::a, $main::b ) );
    }
    if ( not defined $main::b->[$date_num] ) {
        Carp::confess( "sort_items_revchron: blank date (b): " . Dumper( $main::a, $main::b ) );
    }
    try {
        $a_dt = $iso8601->parse_datetime( $main::a->[$date_num] );
    } finally {
        if (@_) {
            Carp::confess( "sort_items_revchron: @_; unparsable a=" . $main::a->[$date_num] . ": " . Dumper($main::a) );
        }
    };
    try {
        $b_dt = $iso8601->parse_datetime( $main::b->[$date_num] );
    } finally {
        if (@_) {
            Carp::confess( "sort_items_revchron: @_; unparsable b=" . $main::b->[$date_num] . ": " . Dumper($main::b) );
        }
    };
    return $b_dt <=> $a_dt;
}

# back to main package
package main;

# run WebFetch to read multiple RSS feeds
my %items;

# call WebFetch to process an RSS feed, filter and save items from it
sub process_feed
{
    my ( $dir, $url ) = @_;
    my %Options = (
        dir           => $dir,
        source_format => "rss",
        source        => $url,
        dest          => "capture",
        dest_format   => "capture",
    );
    WebFetch::RSS->run( \%Options );
    return;
}

#
# main
#
my $debug = 0;
GetOptions( "debug" => \$debug );

# initialize debug mode setting and temporary directory for WebFetch
# Temporary directory is required by WebFetch. But we don't use it, so autoclean to delete after use.
WebFetch::debug_mode($debug);
my $dir = File::Temp->newdir( TEMPLATE => $tmpdir_template, CLEANUP => 1, TMPDIR => 1 );

# process each feed URL
foreach my $rss_url (@rss_urls) {
    process_feed( $dir, $rss_url );
}

# collect WebFetch release history since $release_cutoff time in reverse-chronological order
my @items_revchron;
{
    my @items_unsorted = WebFetch::Output::Capture::news_items();
    @items_revchron =
        sort WebFetch::Output::Capture::sort_items_revchron @items_unsorted;
    WebFetch::debug "RSS items after sort:", Dumper( \@items_revchron );
}

# generate SiteNews file as an example and for use in unit testing
print "# generated by $progname\n";
print "\n";
print "# global configuration\n";
foreach my $global_key ( sort keys %sitenews_global ) {
    print "$global_key: $sitenews_global{$global_key}\n";
}
print "\n";

print "# news items start with attribute assignment lines followed by indented lines of text\n";
foreach my $item (@items_revchron) {
    print "title=" . $item->[$title_num] . "\n";
    print "posted=" . $item->[$date_num] . "\n";
    print "category=release\n";
    print "    <a href=\""
        . $item->[$link_num] . "\">"
        . $item->[$title_num]
        . "</a> released by "
        . $item->[$creator_num] . "\n";
    print "\n";
}
