use v5.40;
use utf8;

use Test2::V0;

use lib 't/lib';
use Test2::Require::WorkingUtf8;

use Encode qw(decode encode is_utf8);
use Log::Any::Test;
use Log::Any qw($log);

use String::License;

# Copyright noise is irrelevant to these tests: we assert that whatever dash
# variant appears in the input, the normalized output contains a canonical
# ASCII hyphen at the same spot. Surrounding text (copyright, names, years)
# is deliberately not pinned down.
sub license_text { String::License->new( string => shift )->as_text }
sub normalized   { String::License->new( string => shift )->string }

# "\Q$_\E" is the literal codepoint; after normalization it must be GONE,
# replaced by a plain "-". We check it at any position inside "BSD-x-Clause".
sub norm_site
{
	my ($d) = @_;
	return index( normalized("BSD$d 3-Clause"), "-" ) >= 0;
}

sub dash_gone
{
	my ($d) = @_;
	return index( normalized("BSD$d 3-Clause"), $d ) < 0;
}

my @DASHES = (
	"\x{2010}", "\x{2011}", "\x{2012}", "\x{2013}", "\x{2014}",
	"\x{2015}", "\x{2212}", "\x{FE58}", "\x{FE63}",    # \p{Dash}
	"\x{02D7}", "\x{2043}", "\x{FE32}", "\x{FF0D}",    # look-alikes
);

subtest 'ascii hyphen control (no normalization)' => sub {
	is normalized("BSD- 3-Clause"), "BSD- 3-Clause", 'untouched';
};

subtest 'BSD resolves when a grant phrase precedes it' => sub {
	my $e = license_text("Licensed under BSD-3-Clause");
	like "$e", qr/BSD-3-Clause/i, 'resolvable BSD via grant phrase';
};

subtest 'unicode dash variants + look-alikes normalize to ASCII hyphen' =>
	sub {
	for my $d (@DASHES) {
		ok norm_site($d), sprintf( 'U+%04X -> "-"',             ord $d );
		ok dash_gone($d), sprintf( 'U+%04X fancy char removed', ord $d );
	}
	};

subtest 'dash soup normalized (UTF-8 en dash as latin1) -> -' => sub {
	my $mojibake = decode 'iso-8859-1', encode( 'UTF-8', "–" );    # U+2013
	ok is_utf8($mojibake), 'input is decoded character string';
	ok index( normalized("BSD$mojibake 3-Clause"), "-" ) >= 0,
		'soup -> hyphen';
	ok index( normalized("BSD$mojibake 3-Clause"), $mojibake ) < 0,
		'soup gone';
};

subtest 'dash soup via CP1252 -> -' => sub {
	my $soup = "\x{E2}\x{20AC}\x{201C}";    # E2 80 93 as CP1252
	ok index( normalized("BSD$soup 3-Clause"), "-" ) >= 0, 'CP1252 -> hyphen';
	ok index( normalized("BSD$soup 3-Clause"), $soup ) < 0, 'CP1252 gone';
};

subtest 'warn fires when dash variants normalized' => sub {
	$log->clear;
	license_text("BSD-\x{2014}3-Clause");
	$log->contains_ok( qr/normalized dash variants/i, 'warn on dash soup' );
	$log->clear;
};

subtest 'warn fires for look-alikes too' => sub {
	$log->clear;
	license_text("BSD-\x{FF0D}3-Clause");
	$log->contains_ok( qr/normalized dash variants/i, 'warn on look-alike' );
	$log->clear;
};

subtest 'no warn on clean license input (hot path silent)' => sub {
	$log->clear;
	license_text("Licensed under the MIT License");
	$log->does_not_contain_ok( qr/normalized dash variants/i, 'no warn' );
	$log->clear;
};

subtest 'lone soup byte sequence does not fabricate a license' => sub {
	for my $s ( "\x{E2}\x{20AC}\x{2122}", "\x{E2}\x{20AC}\x{20AC}" ) {
		my $e = eval { license_text("Some prose with $s and no license") };
		ok( defined($e), 'no crash on lone soup' );
		like "$e", qr/UNKNOWN/, 'no license fabricated from lone soup';
	}
};

done_testing;
