use strict;
use warnings;

use Test::More;

use JQ::Lite;

my $jq = JQ::Lite->new;

sub run {
    my ($json, $query) = @_;
    return [ $jq->run_query($json, $query) ];
}

my $input = '{"num": 6, "den": 2}';
my $success = run($input, 'try .num / .den');

is_deeply(
    $success,
    [3],
    'try returns expression result when no error occurs'
);

my $string_literal = run('null', 'try "catch me"');

is_deeply(
    $string_literal,
    ['catch me'],
    'try ignores catch keywords inside string literals'
);

my $array_literal = run('null', 'try ["catch me"]');

is_deeply(
    $array_literal,
    [['catch me']],
    'try ignores catch keywords inside array literals'
);

my $fail_json = '{"num": 1, "den": 0}';
my $fallback = run($fail_json, 'try (.num / .den)');

is_deeply(
    $fallback,
    [undef],
    'try falls back to null when an error is thrown'
);

my $pipeline = run('{"a": {"b": 2}}', 'try .a.b | . + 1 catch 0');

is_deeply(
    $pipeline,
    [3],
    'try spans a downstream pipeline segment before catch'
);

my $type_error = run('{"a": {"b": "x"}}', 'try .a.b | . + 1 catch 0');

is_deeply(
    $type_error,
    [0],
    'try catches type errors raised by downstream filters'
);

my $with_catch = run($fail_json, 'try (.num / .den) catch $error');

like(
    $with_catch->[0],
    qr/division by zero/i,
    'catch receives the error message via $error'
);

my $catch_filter = run($fail_json, 'try (.num / .den) catch (.den // 1)');

is_deeply(
    $catch_filter,
    [0],
    'catch expression is evaluated as a filter on the original input'
);

my $field_access = run('{"catch": 5}', 'try .catch + 1 catch 0');

is_deeply(
    $field_access,
    [6],
    'try ignores catch when used as a field name'
);


my $nested_try = run($fail_json, 'try try (.num / .den) catch 7 catch 9');

is_deeply(
    $nested_try,
    [7],
    'outer try/catch respects nested try/catch expressions'
);
my $empty_catch = run($fail_json, 'try (.num / .den) catch empty');

is_deeply(
    $empty_catch,
    [],
    'catch can return empty results without forcing null'
);

my $multi_value = run('[{"v": 0}, {"v": 2}]', 'map(try (1 /.v) catch 42)');

is_deeply(
    $multi_value,
    [[42, 0.5]],
    'try works inside other filters and propagates catch results'
);

DONE_TESTING:

if ($ENV{AUTOMATED_TESTING}) {
    done_testing();
} else {
    done_testing();
}
