#!/usr/bin/perl
#
# Copyright (c) 2020  Peter Pentchev <roam@ringlet.net>
# This code is hereby licensed for public consumption under either the
# GNU GPL v2 or greater, or Larry Wall's Artistic license - your choice.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

use v5.12;

use strict;
use warnings;

use File::Temp;
use Path::Tiny;
use Test::Command;
use Test::More;

plan tests => 5;

my $contents = ('A' x 128).('B' x 128);
my $contents_len = length $contents;

sub verify_contents($ $ $)
{
	my ($tag, $fdata, $expected) = @_;

	my $data = $fdata->slurp_utf8;
	my $exp_len = $contents_len + ($expected ? 128 : 0);

	subtest "verify data file: $tag" => sub {
		plan tests => 3;

		is length $data, $exp_len,
		    "The file is $exp_len characters long";
		is substr($data, 0, $contents_len), $contents,
		    'The file starts with the expected contents';

		SKIP: {
			skip 'No tag yet', 1 unless $expected;
			is substr($data, $contents_len, 3), 'TAG',
			    'The file contains the ID3 tag marker';
		}
	};
}

my $RE_TAG = qr{^
	(?<tag>
		Song \s Title
		|
		[A-Za-z ]+
	)
	: \s
	(?<value_full>
		(?<ws_before> \s* )
		(?<value> .*? )
		(?<ws_after> \s* )
	)
$}x;

sub extract_file_tag_stripped($)
{
	my ($lines) = @_;

	my %data;
	subtest 'parse an RFC-822-like tag' => sub {
		if (!@{$lines}) {
			fail 'any lines';
			return;
		}

		while (@{$lines}) {
			my $line = shift @{$lines};
			last if $line eq '';
			if ($line !~ $RE_TAG) {
				like $line, $RE_TAG, 'tag: value line';
				return;
			}
			my ($tag, $value) = ($+{tag}, $+{value});
			ok 1, "got a $tag line";
			$data{$tag} = $value;
		}
		fail 'any tag/value lines' unless %data;
	};

	return \%data;
}

my $PROG = $ENV{TEST_ID3} // './id3';
BAIL_OUT "Not an executable file: $PROG" unless -f $PROG && -x $PROG;

my $tempd = File::Temp->newdir('id3test.XXXXXX', TMPDIR => 1);
my $fdata = path($tempd)->child('data.dat');
$fdata->spew_utf8($contents);

verify_contents 'initial', $fdata, undef;

subtest 'List a file with no tag' => sub {
	plan tests => 3;

	my $cmd = [$PROG, '--', $fdata];
	my $tcmd = Test::Command->new(cmd => $cmd);
	$tcmd->exit_is_num(0, '-l succeeded');

	my @lines = split /\r*\n/, $tcmd->stdout_value;
	ok scalar @lines < 5, 'output less than five lines';
	like $tcmd->stdout_value, qr{No ID3 Tag}, 'said No ID3 Tag';
};

my %tag_data = (
	Filename => "$fdata",
	'Song Title' => 'Tenser, said the Tensor',
	Artist => 'Duffy Wyg&',
	Album => 'The Demolished Man',
	Year => '2301',
	Track => '1',
	Genre => 'Dream (0x37)',
	Note => 'Tension, apprehension, and dissension',
);

subtest 'Add a tag' => sub {
	plan tests => 2;

	my $cmd = [
		$PROG,
		'-r', $tag_data{Artist},
		'-a', $tag_data{Album},
		'-y', $tag_data{Year},
		'-c', $tag_data{Track},
		'-t', $tag_data{'Song Title'},
		'-g', '55',
		'-n', $tag_data{Note},
		'--', $tag_data{Filename},
	];
	my $tcmd = Test::Command->new(cmd => $cmd);
	$tcmd->exit_is_num(0, 'add succeeded');

	# Cut the comment down to size
	$tag_data{Note} = substr($tag_data{Note}, 0, 28);

	is $tcmd->stdout_value, '', 'add output no lines';
};

verify_contents 'added', $fdata, \%tag_data;

subtest 'List the added tag' => sub {
	plan tests => 5;

	my $cmd = [$PROG, '--', $fdata];
	my $tcmd = Test::Command->new(cmd => $cmd);
	$tcmd->exit_is_num(0, 'succeeded');

	my @lines = split /\r*\n/, $tcmd->stdout_value;
	ok @lines >= 2, 'output at least two lines';

	my $tag = extract_file_tag_stripped \@lines;
	is_deeply $tag, \%tag_data, 'read the added data';
	is_deeply \@lines, [], 'no more lines';
};
