#!/usr/bin/env perl

use strict;
use warnings;

use Getopt::Long qw(GetOptions :config pass_through);
use Pod::Usage;
use JSON::PP;
use GDPR::IAB::TCFv2;

use constant {
    EXIT_SUCCESS     => 0,
    EXIT_PARSE_ERROR => 1,
};

my %opts = (
    pretty             => 0,
    'json-array'       => 0,
    'ignore-errors'    => 0,
    'fail-fast'        => 0,
    'errors-to-stderr' => 0,
    'quiet'            => 0,
);

GetOptions(
    'pretty'             => \$opts{pretty},
    'json-array|bulk'    => \$opts{'json-array'},
    'ignore-errors|i'    => \$opts{'ignore-errors'},
    'fail-fast|f'        => \$opts{'fail-fast'},
    'errors-to-stderr|e' => \$opts{'errors-to-stderr'},
    'quiet|q'            => \$opts{'quiet'},
    'help|h'             => sub { pod2usage(1) },
    'man'                => sub { pod2usage( -exitval => 0, -verbose => 2 ) },
) or pod2usage(2);

my $json = JSON::PP->new->utf8;
$json->pretty(1)->indent_length(4) if $opts{pretty};

if ( $opts{'json-array'} ) {
    print "[\n";
}

my $count    = 0;
my $line_num = 0;

if (@ARGV) {
    foreach my $str (@ARGV) {
        $line_num++;
        process_string( $str, $line_num );
    }
}
else {
    binmode( STDIN, ':utf8' ) if -t STDIN;
    while ( my $line = <STDIN> ) {
        $line_num++;
        chomp $line;
        next unless $line =~ /\S/;
        process_string( $line, $line_num );
    }
}

if ( $opts{'json-array'} ) {
    print "\n]\n";
}

exit EXIT_SUCCESS;

sub process_string {
    my ( $str, $num ) = @_;
    my $output_data;

    eval {
        my $tcf = GDPR::IAB::TCFv2->Parse($str);
        $output_data = $tcf->TO_JSON;
    };
    if ( my $err = $@ ) {
        if ( $opts{'fail-fast'} ) {
            warn
              "Fatal: Failed to parse TC string '$str' at line $num: $err\n";
            exit EXIT_PARSE_ERROR;
        }

        warn "Warning: Failed to parse TC string '$str' at line $num: $err\n"
          unless $opts{'quiet'};

        next if $opts{'ignore-errors'};

        chomp $err;
        $output_data = {
            tc_string => $str,
            error     => $err,
            success   => JSON::PP::false
        };

        if ( $opts{'errors-to-stderr'} ) {
            warn $json->encode($output_data) . "\n";
            return;
        }
    }

    my $out = $json->encode($output_data);

    if ( $opts{'json-array'} ) {
        print(",\n") if $count > 0;
        print( $opts{pretty} ? _indent($out) : $out );
    }
    else {
        print "$out\n";
    }

    $count++;
}

sub _indent {
    my $text = shift;
    $text =~ s/^/    /mg;
    return $text;
}

__END__

=head1 NAME

iabtcf-dump - Parses TC strings and outputs them as JSON

=head1 SYNOPSIS

iabtcf-dump [options] [tc_strings...]

=head1 OPTIONS

=over 4

=item B<--pretty>

Output human-readable, indented JSON.

=item B<--json-array>, B<--bulk>

Output a single JSON array containing all parsed objects.

=item B<--ignore-errors>, B<-i>

Do not output any JSON error object for failed strings.

=item B<--fail-fast>, B<-f>

Stop processing and exit the program immediately upon the first parse error.

=item B<--errors-to-stderr>, B<-e>

Output JSON error objects to B<STDERR> instead of B<STDOUT>.

=item B<--quiet>, B<-q>

Suppress human-readable warning messages on B<STDERR>.

=item B<--help>, B<-h>

Print a brief help message and exits.

=item B<--man>

Prints the manual page and exits.

=back

=head1 DESCRIPTION

B<iabtcf-dump> is a command-line utility for the GDPR::IAB::TCFv2 library.
It allows you to parse IAB Transparency and Consent (TC) strings and convert them
into JSON format for easy inspection or further processing with tools like C<jq>.

=head1 EXAMPLES

    # Dump a string to JSON line
    iabtcf-dump CPi...AAA

    # Dump multiple strings to a pretty-printed JSON array
    iabtcf-dump --pretty --json-array CPi...AAA CPj...BBB

    # Read from STDIN
    cat strings.txt | iabtcf-dump --json-array

=cut
