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

# Regression tests for driver-specific SQL/DSN generation:
#  - rank 6:  _make_dsn must build a ';'-separated DSN with host and port.
#  - rank 12: _dsn_to_dbi must not truncate a password containing ':'.
#  - rank 13: the UTF-8 flag must map to the driver-appropriate attribute.
#  - rank 15: the mysql upsert clause must use the row-alias form, not VALUES().

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,
);

subtest 'rank 6: _make_dsn builds a proper ;-separated DSN with host/port' => sub {
    is($db->_make_dsn({ driver => 'MariaDB', db => 'mydb', host => 'localhost', port => 3306 }),
       'dbi:MariaDB:dbname=mydb;host=localhost;port=3306',
       'MariaDB DSN is ;-separated and includes the port');

    is($db->_make_dsn({ driver => 'Pg', db => 'app', host => '10.0.0.1' }),
       'dbi:Pg:dbname=app;host=10.0.0.1',
       'Pg DSN without port');

    is($db->_make_dsn({ driver => 'SQLite', db => '/tmp/x.db' }),
       'dbi:SQLite:dbname=/tmp/x.db',
       'SQLite DSN unchanged');
};

subtest 'rank 12: _dsn_to_dbi keeps a password containing a colon' => sub {
    $db->_dsn_to_dbi('mariadb://user:pa:ss:word@host:3306/dbname');
    is($db->args->{Auth}{user},     'user',       'user parsed');
    is($db->args->{Auth}{password}, 'pa:ss:word', 'password with colons not truncated');
};

subtest 'rank 13: UTF-8 flag maps to the driver-appropriate attribute' => sub {
    {
        package TinyDBH;
        sub new { bless {}, shift }
        sub quote { }
        sub trace { }
    }
    {
        package TinyConn;
        sub new  { bless { d => $_[1] }, $_[0] }
        sub dbh  { $_[0]->{d} }
        sub mode { }
    }

    my $maria = DBIx::Fast->new(
        dsn               => 'dbi:MariaDB:dbname=x;host=h',
        db                => TinyConn->new(TinyDBH->new),
        mysql_enable_utf8 => 1,
    );
    ok($maria->args->{DBI}{mariadb_enable_utf8mb4},
       'MariaDB -> mariadb_enable_utf8mb4');
    ok(!$maria->args->{DBI}{mysql_enable_utf8},
       'legacy mysql_enable_utf8 NOT set for MariaDB (DBD::MariaDB ignores it)');

    my $mysql = DBIx::Fast->new(
        dsn               => 'dbi:mysql:dbname=x;host=h',
        db                => TinyConn->new(TinyDBH->new),
        mysql_enable_utf8 => 1,
    );
    ok($mysql->args->{DBI}{mysql_enable_utf8mb4},
       'mysql -> mysql_enable_utf8mb4');
};

subtest 'rank 15 / R2.5: mysql upsert clause is version-gated' => sub {
    # A tiny handle that controls mysql_serverversion and quotes with backticks,
    # so we can exercise both gate branches deterministically without live MySQL.
    {
        package VerDBH;
        sub new              { bless { mysql_serverversion => $_[1] }, $_[0] }
        sub quote_identifier { "`$_[1]`" }
        sub quote            { }
        sub trace            { }
    }
    {
        package VerConn;
        sub new  { bless { d => $_[1] }, $_[0] }
        sub dbh  { $_[0]->{d} }
        sub mode { }
    }

    my $modern = DBIx::Fast->new(
        dsn => 'dbi:mysql:dbname=x;host=h', db => VerConn->new(VerDBH->new(80035)));
    my $c = $modern->_upsert_clause(['sku'], ['stock', 'price']);
    like($c,   qr/\bAS\s+new\b/, 'MySQL >= 8.0.19 uses the row-alias form');
    like($c,   qr/=\s*new\./,    'sets columns from new.<col>');
    unlike($c, qr/VALUES\s*\(/,  'no deprecated VALUES() on modern MySQL');

    my $old = DBIx::Fast->new(
        dsn => 'dbi:mysql:dbname=x;host=h', db => VerConn->new(VerDBH->new(80018)));
    my $c2 = $old->_upsert_clause(['sku'], ['stock']);
    like($c2,   qr/VALUES\(/, 'MySQL < 8.0.19 falls back to VALUES() (no syntax error)');
    unlike($c2, qr/AS\s+new/, 'no row-alias on old MySQL');

    # MariaDB always keeps VALUES() (it lacks the row-alias syntax).
    my $maria = DBIx::Fast->new(
        dsn => 'dbi:MariaDB:dbname=x;host=h', db => VerConn->new(VerDBH->new(0)));
    like($maria->_upsert_clause(['sku'], ['stock']), qr/VALUES\(/,
       'MariaDB still emits VALUES(col)');
};

subtest 'Wave0: postgres:// and postgresql:// URIs construct (resolve to Pg)' => sub {
    # Found while validating against a live PostgreSQL: constructing with a
    # postgres:// URI used to throw "Error DBD Driver : postgres" because
    # _dsn_to_dbi called _Driver_dbd($scheme) before the scheme->driver mapping.
    for my $scheme (qw(postgres postgresql)) {
        my $pg = DBIx::Fast->new(
            dsn => "$scheme://u:p\@h:5432/dbix",
            db  => TinyConn->new(TinyDBH->new),
        );
        is($pg->dbd, 'Pg', "$scheme:// resolves the driver to Pg");
        is($pg->args->{Auth}{user},     'u', "$scheme:// parses the user");
        is($pg->args->{Auth}{password}, 'p', "$scheme:// parses the password");
    }

    my $mx = DBIx::Fast->new(
        dsn => 'mysqlx://u:p@h:33060/dbix',
        db  => TinyConn->new(TinyDBH->new),
    );
    is($mx->dbd, 'mysql', 'mysqlx:// resolves the driver to mysql');
};

done_testing;
