use strict;
use warnings;
use Test::More;
use Test::Exception;
use DBIx::Fast;

# Regression tests for count()/_make_where (ranks 4, 32) and the silenceable
# Exception() validation bypass (rank 5).

eval "use DBD::SQLite 1.74";
plan skip_all => "DBD::SQLite 1.74 required" if $@;

my $db = DBIx::Fast->new(
    dsn        => 'dbi:SQLite:dbname=:memory:',
    driver     => 'SQLite',
    RaiseError => 1,
    PrintError => 0,
);

$db->exec('CREATE TABLE t (id INTEGER PRIMARY KEY, n INTEGER, label TEXT)');
$db->exec('INSERT INTO t (id, n, label) VALUES (1, 10,  ?)', 'a');
$db->exec('INSERT INTO t (id, n, label) VALUES (2, 50,  ?)', 'b');
$db->exec('INSERT INTO t (id, n, label) VALUES (3, 100, ?)', 'c');
$db->exec('INSERT INTO t (id, n, label) VALUES (4, 200, NULL)');   # NULL label

subtest 'rank 4: BETWEEN emits two placeholders and counts the range' => sub {
    my $c;
    lives_ok { $c = $db->count('t', { n => { BETWEEN => [10, 100] } }) }
        'BETWEEN does not crash';
    is($c, 3, 'BETWEEN [10,100] counts the inclusive range');
    like($db->sql, qr/BETWEEN \? AND \?/, 'emits "BETWEEN ? AND ?"');
};

subtest 'rank 4: undef collapses to IS NULL' => sub {
    my $c = $db->count('t', { label => undef });
    is($c, 1, 'plain undef counts NULL rows (IS NULL, not "= NULL")');
    like($db->sql, qr/IS NULL/, 'emits IS NULL');

    is($db->count('t', { label => { IS => undef } }), 1,
       '{IS => undef} also counts NULL rows');
};

subtest 'rank 4: != undef collapses to IS NOT NULL' => sub {
    my $c = $db->count('t', { label => { '!=' => undef } });
    is($c, 3, '{"!=" => undef} counts NON-NULL rows (IS NOT NULL)');
    like($db->sql, qr/IS NOT NULL/, 'emits IS NOT NULL');
};

subtest 'rank 32: WHERE column identifier is quoted' => sub {
    $db->count('t', { n => 50 });
    like($db->sql, qr/"n"/, 'WHERE column is quote_identifier-quoted');
};

subtest 'rank 5: Exception always throws, even with RaiseError=0 & PrintError=0' => sub {
    my $silent = DBIx::Fast->new(
        dsn        => 'dbi:SQLite:dbname=:memory:',
        driver     => 'SQLite',
        RaiseError => 0,
        PrintError => 0,
    );

    throws_ok { $silent->_safe_id('a; DROP TABLE x') }
        qr/Invalid identifier/,
        '_safe_id still aborts in silent mode (no validation bypass)';

    throws_ok { $silent->Exception('boom') }
        qr/Exception: boom/,
        'Exception() always croaks';
};

subtest 'R2.3: a dotted WHERE column is quoted per segment' => sub {
    my $c = $db->count('t', { 't.n' => 50 });
    is($c, 1, 'qualified column t.n counts correctly');
    like($db->sql, qr/"t"\."n"/, 'emits "t"."n" (quoted per segment)');
    unlike($db->sql, qr/"t\.n"/, 'does not wrap the dotted name as one identifier');
};

subtest 'R2.4: multiple operators in one column hashref are rejected' => sub {
    throws_ok { $db->count('t', { n => { '>' => 1, '<' => 100 } }) }
        qr/[Mm]ultiple operators/,
        'an ambiguous multi-operator hashref croaks instead of silently dropping one';
};

done_testing;
