#!/usr/bin/perl

use strict;
use warnings;
use autodie;

use Getopt::Long;

BEGIN {
    $ENV{'LINTIAN_ROOT'} //= '.';
}
use lib "$ENV{'LINTIAN_ROOT'}/lib/";
use Lintian::Command qw(safe_qx);

my $RE = qr{
    \A [ ]{2,}  XXX: [ ] generate [ ] tag [ ] summary
    (?:[ ] with [ ] private/generate-tag-summary)? \s* \n \Z
}xsm;
my (%added, %removed, %opt);

my %opthash = ('in-place|i' => \$opt{'in-place'},);

# init commandline parser
Getopt::Long::config('bundling', 'no_getopt_compat', 'no_auto_abbrev',
    'permute');

# process commandline options
Getopt::Long::GetOptions(%opthash)
  or die("error parsing options\n");

my ($commit_range) = @ARGV;
if (not $commit_range) {
    my $describe = safe_qx(qw(git describe --abbrev=0));
    if ($? != 0) {
        die 'git describe failed with code ' . (($? >> 8) & 0xff);
    }
    chomp($describe);
    if (not $describe) {
        die "git describe did not return anything.\n";
    }
    $commit_range = "${describe}..HEAD";
    print "Assuming commit range to be: ${commit_range}\n";
}

open(my $fd, '-|', 'git', 'diff', $commit_range, '--', 'checks/*.desc');
while (my $line = <$fd>) {
    chomp($line);
    next unless $line =~ m{ \A ([\+-]) Tag: \s*+ ([^ ]++) \s*+ \Z}xsm;
    my ($change, $tag) = ($1, $2);
    if ($change eq '+') {
        $added{$tag} = 1;
    } else {
        $removed{$tag} = 1;
    }
}
close($fd);

for my $tag (keys(%added)) {
    if (exists($removed{$tag})) {
        # Added and removed?  More likely, the tag was moved between
        # two files.
        delete($added{$tag});
        delete($removed{$tag});
    }
}

if (not %added and not %removed) {
    print STDERR "No tags were added or removed\n";
}

if ($opt{'in-place'}) {
    my $matched = 0;
    open(my $in_fd, '<', 'debian/changelog');
    open(my $out_fd, '>', 'debian/changelog.tmp');
    while (my $line = <$in_fd>) {
        if ($line =~ m/$RE/o) {
            emit_tag_summary($out_fd);
            $matched++;
        } else {
            print {$out_fd} $line;
        }
    }
    close($out_fd);
    close($in_fd);
    if ($matched != 1) {
        die("changelog did not match $RE exactly once\n");
    }
    rename('debian/changelog.tmp', 'debian/changelog');
    print "Updated debian/changelog\n";
} else {
    emit_tag_summary(\*STDOUT);
}

sub emit_tag_summary {
    my ($fd) = @_;

    if (%added or %removed) {
        print {$fd} "  * Summary of tag changes:\n";
    }
    if (%added) {
        print {$fd} "    + Added:\n";
        for my $tag (sort(keys(%added))) {
            print {$fd} "      - $tag\n";
        }
    }
    if (%removed) {
        print {$fd} "    + Removed:\n";
        for my $tag (sort(keys(%removed))) {
            print {$fd} "      - $tag\n";
        }
    }
    return;
}
