use strict;
use warnings;

use Test::More;
use Test::Exception;
use JSON::PP;
use FindBin;
use File::Spec;
use IO::Uncompress::Gunzip qw($GunzipError);
use lib 'lib';
use GDPR::IAB::TCFv2;

# The golden corpus is shipped gzipped (~16x smaller).  To inspect a regen
# diff locally:
#   gunzip -c t/corpus/golden.jsonl.gz | diff - <(git show HEAD:t/corpus/golden.jsonl.gz | gunzip -c)
my $corpus_dir  = File::Spec->catdir($FindBin::Bin, 'corpus');
my $golden_file = File::Spec->catfile($corpus_dir, 'golden.jsonl.gz');

# Support regeneration via environment variable
if ($ENV{REGEN_CORPUS}) {
  diag("Regenerating corpus...");
  my $generator = File::Spec->catfile($FindBin::Bin, 'generate_golden.pl');
  system($^X, '-Ilib', $generator) == 0 or die "Failed to regenerate corpus: $!";
}

if (!-f $golden_file) {
  plan skip_all => "Golden file $golden_file not found";
}

my $fh   = IO::Uncompress::Gunzip->new($golden_file) or die "Could not open $golden_file: $GunzipError";
my $json = JSON::PP->new->utf8;

my $count = 0;
while (my $line_json = <$fh>) {
  chomp $line_json;
  next unless $line_json;

  my $entry     = $json->decode($line_json);
  my $tc_string = $entry->{tc_string};

  $count++;

  if ($entry->{expect_failure}) {
    throws_ok { GDPR::IAB::TCFv2->Parse($tc_string); }
    qr/\Q$entry->{error_match}\E/, "String $count should fail as expected";
  }
  else {
    my $consent;
    lives_ok {
      $consent = GDPR::IAB::TCFv2->Parse($tc_string, json => {boolean_values => [JSON::PP::false, JSON::PP::true]});
    }
    "String $count parsed successfully";

    next unless $consent;

    my $tests = $entry->{tests};

    # Test JSON representation
    is_deeply_with_diag($consent->TO_JSON, $tests->{to_json}, "String $count: TO_JSON match");

    # Test metadata
    is($consent->version,         $tests->{metadata}->{version},       "String $count: version match");
    is($consent->cmp_id,          $tests->{metadata}->{cmp_id},        "String $count: cmp_id match");
    is(scalar($consent->created), $tests->{metadata}->{created_epoch}, "String $count: created match");

    # Test sampling
    my $sampling = $tests->{sampling};
    foreach my $key (keys %{$sampling}) {
      if ($key eq 'purpose_1_consent') {
        is(!!$consent->is_purpose_consent_allowed(1), !!$sampling->{$key}, "String $count: $key match");
      }
      elsif ($key eq 'vendor_284_consent') {
        is(!!$consent->vendor_consent(284), !!$sampling->{$key}, "String $count: $key match");
      }
      elsif ($key eq 'vendor_284_purpose_1_allowed' && $consent->can('is_vendor_consent_allowed')) {
        is(!!$consent->is_vendor_consent_allowed(284, 1), !!$sampling->{$key}, "String $count: $key match");
      }
    }
  }
}

sub is_deeply_with_diag {
  my ($got, $expected, $name) = @_;
  if (!is_deeply($got, $expected, $name)) {
    diag("\n" . ("!" x 60));
    diag("GOLDEN FILE MISMATCH DETECTED");
    diag("If this is expected (e.g. intentional logic change), regenerate the corpus with:");
    diag("  REGEN_CORPUS=1 prove -l $0");
    diag(("!" x 60) . "\n");
    return 0;
  }
  return 1;
}

done_testing;
