#!/usr/bin/env perl

use strict;
use warnings;

use CPAN::DistnameInfo;
use Data::Dumper;
use File::Basename qw(basename);
use HTTP::Tiny;
use JSON ();
use PerlIO::gzip;
use YAML::Tiny;

local $Data::Dumper::Sortkeys = 1;

my @files = my @args = ($^O eq 'MSWin32') ? map { glob } @ARGV : @ARGV;
die "Usage: <files>\n" unless @files;

my %db;
foreach my $file (@files) {
	print STDERR "Processing $file...\n";
    my $yaml = YAML::Tiny->read($file)->[0];

    my $dist = basename $file;
    $dist =~ s{^CPANSA-}{};
    $dist =~ s{\.yml$}{};

    $db{dists}->{$dist}->{advisories} = $yaml;
}

provides( \%db );

foreach my $dist ( keys %{ $db{dists} } ) {
    $db{dists}->{$dist}->{versions} = [ all_releases($dist) ];
    $db{dists}->{$dist}->{main_module} = release($dist)->{main_module};
}

# XXX: need to investigate why this shows up as utf8
$db{dists}->{'perl'}->{main_module} = 'perl';

my $dump = Dumper( \%db );
$dump =~ s{^\$VAR1\s*=\s*}{};
$dump =~ s{}{};

my $submodule_dir = 'cpan-security-advisory';

my( $commit ) = split /\s+/, join '', grep { /\Q$submodule_dir/ } `git submodule status`;

my( $year, $month, $day ) = (localtime)[5,4,3];
my( $version ) = sprintf '%4d%02d%02d', $year + 1900, $month + 1, $day;

print <<"EOF";
# created by $0 at @{[ scalar localtime]}
# $submodule_dir $commit
#
package CPAN::Audit::DB;

use strict;
use warnings;

our \$VERSION = '$version';

sub db {
    $dump
}

1;
EOF

sub provides {
    my ($db) = @_;

    my $ua = HTTP::Tiny->new;

    my $details_file = '/tmp/02packages.details.txt.gz';
	print STDERR "Downloading 02packages.details.txt.gz (this may take awhile)\n";
    $ua->mirror( 'http://www.cpan.org/modules/02packages.details.txt.gz',
        $details_file );
	print STDERR "Downloaded 02packages.details.txt.gz\n";
	print STDERR "Digesting 02packages.details.txt.gz (this may take awhile)\n";

    open my $fh, '<:gzip', $details_file
      or die "Can't open '$details_file': $!";

    while ( defined( my $line = <$fh> ) ) {
        chomp $line;

        last if $line eq '';
    }

    while ( defined( my $line = <$fh> ) ) {
        my ( $module, $version, $pathname ) = split /\s+/, $line;
        next unless $module && $pathname;

        my $dist_info = CPAN::DistnameInfo->new($pathname);
        next unless $dist_info;

        my $author = $dist_info->cpanid;
        my $dist   = $dist_info->dist;
        my $name   = $dist_info->distvname;

        next unless $dist;

        next unless $db->{dists}->{$dist};

        $db->{module2dist}->{$module} = $dist;
    }

    close $fh;
}

sub release {
    my ($distribution) = @_;

    my $response = HTTP::Tiny->new->get(
        'http://fastapi.metacpan.org/v1/release/' . $distribution );

    my $content_json = JSON::decode_json( $response->{content} );

    return $content_json;
}

sub all_releases {
    my ($distribution) = @_;

    my $response = HTTP::Tiny->new->post(
        'http://fastapi.metacpan.org/v1/release/_search',
        {
            headers => { 'Content-Type' => 'application/json' },
            content => JSON::encode_json(
                {
                    size   => 5000,
                    fields => [ 'date', 'version' ],
                    filter => {
                        term => { distribution => $distribution }
                    }
                }
            )
        }
    );

    my $content_json = JSON::decode_json( $response->{content} );

    my @results =
      sort { $a->{date} cmp $b->{date} }
      map  { $_->{fields} } @{ $content_json->{hits}->{hits} };
    return unless @results;

    return @results;
}
