#!/usr/bin/perl

use strict;
use warnings;
use Debian::PkgJs::Lib;
use Debian::PkgJs::Npm;
use Getopt::Std;
use JSON;
use threads;

BEGIN {
    eval '
use Devscripts::Uscan::Config;
use Devscripts::Uscan::FindFiles;
use Devscripts::Uscan::Output;
use Devscripts::Uscan::WatchFile;
';
    if ($@) {
        print STDERR "Install devscripts to use $0\n";
        exit 1;
    }
}

my ( $res, @npmthr, @gitthr, $exit, $watchLines, %opt );

getopts( 'hg', \%opt );
if ( $opt{h} or ( not @ARGV ) ) {
    print <<EOF;
Usage: $0 <node-modules-to-add-as-component>

Options:
 * -g: install new component with "group" at the end of debian/watch line
       (see uscan(1) for more)
 * -h: print this
EOF
    exit( $opt{h} ? 0 : 1 );
}

my $target = $opt{g} ? 'group' : 'ignore';

foreach my $cmp (@ARGV) {
    push @npmthr, threads->create( sub { npmrepo($cmp) } );
}

my @comp = @ARGV;

$watchLines = getWatchLines();
my @cmpnames = map { $_->component ? $_->component : () } @$watchLines;

foreach my $cmp (@comp) {
    my $thr = shift @npmthr;
    my ( $latest, $tmp ) = $thr->join();
    my $cmpname = $cmp;
    $cmpname =~ s/[^\w\-]//g;
    if ( grep { $cmpname eq $_ } @cmpnames ) {
        print STDERR "Component $cmpname already exists, skipping\n";
        $exit++;
        push @gitthr, threads->create( sub { undef } );
        next;
    }
    $tmp or die "Component $cmp not found in npm registry";
    my $repo = eval { url_part($tmp) };
    if ($@) {
        print STDERR "Unable to add $cmp: unable to parse $tmp\n";
        $exit++;
        push @gitthr, threads->create( sub { undef } );
    }
    $res->{$cmp}->{npmrepo}   = $repo;
    $res->{$cmp}->{npmlatest} = $latest;
    push @gitthr, threads->create( sub { git_last_version($repo) } );
}

my @component_added;
foreach my $cmp (@comp) {
    my $thr = shift @gitthr;
    my ($gitlatest) = $thr->join();
    unless ($gitlatest) {
        print STDERR "Unable to add $cmp\n";
        $exit++;
        next;
    }
    my $cmpname = $cmp;
    $cmpname =~ s/[^\w\-]//g;
    my $check = ( Dpkg::Version->new( "$gitlatest-0", check => 0 )
          <=> Dpkg::Version->new( "$res->{$cmp}->{npmlatest}-0", check => 0 ) );
    my $cmp_watch = "\n"
      . (
        $check
        ? registry_watch( $res->{$cmp}->{npmrepo}, $cmpname, $target )
        : git_watch( $res->{$cmp}->{npmrepo}, $cmpname, $target )
      );
    my $f;
    open $f, '>>', 'debian/watch' or die $!;
    print $f $cmp_watch;
    close $f;
    push @component_added, $cmpname;
}

eval { require Config::IniFiles };
if($@) {
    print STDERR "Missing libconfig-inifiles-perl, skipping gbp.conf update";
    exit 1;
}

if (@component_added) {
    if ( $opt{g}
        and not( $watchLines->[0]->type and $watchLines->[0]->type eq 'group' )
      )
    {
        print STDERR
qq'Main debian/watch seems not tagged as "group", you should verify this\n';
        $exit++;
    }
    unless ( -e 'debian/gbp.conf' ) {
        my $f;
        open $f, '>', 'debian/gbp.conf' or die $!;
        print $f <<EOF;
[DEFAULT]
pristine-tar = True
sign-tags = True

[import-orig]
filter = [ '.gitignore', '.travis.yml', '.git*' ]
EOF
    }
    my $cfg = Config::IniFiles->new( -file => 'debian/gbp.conf' );
    $cfg->AddSection('DEFAULT');
    my $val = $cfg->val( 'DEFAULT', 'component' ) || '';
    my @cmp = ( $val =~ /([\w\-\.]+)/g );
    $cfg->delval( 'DEFAULT', 'component' );
    $cfg->newval( 'DEFAULT', 'component',
        '[' . join( ', ', map { "'$_'" } ( @cmp, @component_added ) ) . ']' );
    $cfg->WriteConfig('debian/gbp.conf');
    print STDERR "Components added: " . join( ', ', @component_added ) . "\n";
}

exit $exit if $exit;

sub getWatchLines {
    @ARGV = ();
    my $config = Devscripts::Uscan::Config->new->parse;
    my @wf     = find_watch_files($config);
    my ( $pkg_dir, $package, $version, $watchfile ) = @{ $wf[0] };
    chdir $pkg_dir;
    my $watchFile = Devscripts::Uscan::WatchFile->new(
        {
            config      => $config,
            package     => $package,
            pkg_dir     => $pkg_dir,
            pkg_version => $version,
            watchfile   => $watchfile,
        }
    );
    my $watchLines = $watchFile->watchlines;
    $_->parse foreach (@$watchLines);
    return ($watchLines);
}
