package Mediabot::DB;

use strict;
use warnings;
use DBI;

# CHARSET_MODE:
#   utf8mb4 (défaut) -> SET NAMES utf8mb4, etc.
#   latin1           -> SET NAMES latin1 (compat héritage)
#   off              -> ne touche pas au charset/collation de session

sub new {
    my ($class, $conf, $logger) = @_;
    my $self = {
        conf   => $conf,
        logger => $logger,
        dbh    => undef,
    };
    bless $self, $class;

    my $dbname = $conf->get('mysql.MAIN_PROG_DDBNAME') || '';
    my $dbhost = $conf->get('mysql.MAIN_PROG_DBHOST')  || 'localhost';
    my $dbuser = $conf->get('mysql.MAIN_PROG_DBUSER')  || '';
    my $dbpass = $conf->get('mysql.MAIN_PROG_DBPASS')  || '';
    my $dbport = $conf->get('mysql.MAIN_PROG_DBPORT')  || 3306;

    # Commutateur de compatibilité (configurable dans mediabot.conf)
    my $mode = lc($conf->get('mysql.CHARSET_MODE') // 'utf8mb4');   # utf8mb4 | latin1 | off
    $self->{charset_mode} = $mode;

    unless ($dbname && $dbuser) {
 $logger->log(0, " Missing DB configuration: DDBNAME or DBUSER is undefined.");
        $logger->log(0, "Check your [mysql] section in mediabot.conf");
        exit 1;
    }

    $logger->log(1, "Connecting to DB: $dbname at $dbhost:$dbport (charset_mode=$mode)");

    # DBD::MariaDB refuses port when host=localhost (uses Unix socket instead)
    # Force TCP by converting localhost to 127.0.0.1
    my $tcp_host = ($dbhost eq 'localhost') ? '127.0.0.1' : $dbhost;
    my $dsn = "DBI:MariaDB:database=$dbname;host=$tcp_host;port=$dbport";

    my %attrs = (
        RaiseError           => 0,
        PrintError           => 0,
        AutoCommit           => 1,
        mariadb_auto_reconnect => 1,
        # Active seulement en mode utf8mb4 (sinon on laisse à 0)
    );

    my $dbh = DBI->connect($dsn, $dbuser, $dbpass, \%attrs);
    if (!$dbh) {
 $logger->log(0, " DBI connect failed: " . $DBI::errstr);
        $logger->log(0, "Check your credentials in mediabot.conf");
        $logger->log(0, "Aborting startup.");
        exit 1;
    }

    # Appliquer le charset/collation de session selon le mode choisi
    _apply_session_charset($dbh, $logger, $mode);

    # Log de vérif (collation de session)
    eval {
        my $sth = $dbh->prepare("SHOW VARIABLES LIKE 'collation_connection'");
        if ($sth->execute) {
            my (undef, $value) = $sth->fetchrow_array;
            $logger->log(3, "  DB collation in use: $value");
        }
        $sth->finish;
        1;
    } or do {
        $logger->log(1, "Warn: couldn't read collation_connection ($@)");
    };

    $self->{dbh} = $dbh;
    $logger->log(3, " DBI connection successful");

    return $self;
}

sub _apply_session_charset {
    my ($dbh, $logger, $mode) = @_;

    my @sql;
    if ($mode eq 'utf8mb4') {
        @sql = (
            'SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci',
            'SET CHARACTER SET utf8mb4',                       # ⚠️ sans apostrophe orpheline
            'SET COLLATION_CONNECTION = utf8mb4_unicode_ci',
        );
    }
    elsif ($mode eq 'latin1') {  # compat héritage si des hashes ont été faits en latin1
        @sql = (
            'SET NAMES latin1',
            'SET CHARACTER SET latin1',
            'SET COLLATION_CONNECTION = latin1_swedish_ci',
        );
    }
    elsif ($mode eq 'off') {
        # Ne change rien — garder la session telle quelle
        $logger->log(2, "Charset mode OFF: leaving session charset/collation untouched");
        return;
    } else {
        # Valeur inattendue -> fallback utf8mb4
        $logger->log(0, "Unknown CHARSET_MODE '$mode', falling back to utf8mb4 -- check [mysql] in mediabot.conf");
        @sql = (
            'SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci',
            'SET CHARACTER SET utf8mb4',
            'SET COLLATION_CONNECTION = utf8mb4_unicode_ci',
        );
    }

    foreach my $stmt (@sql) {
        my $sth = $dbh->prepare($stmt);
        unless ($sth && $sth->execute) {
            $logger->log(1, "SQL error during init: $DBI::errstr (query: $stmt)");
        }
        $sth->finish if $sth;
    }
}

# Reconnexion (même signature que l'implémentation précédente si tu l'appelais)
sub _connect {
    my ($self) = @_;
    my $conf   = $self->{conf};
    my $logger = $self->{logger};

    my $dbname = $conf->get('mysql.MAIN_PROG_DDBNAME') || '';
    my $dbhost = $conf->get('mysql.MAIN_PROG_DBHOST')  || 'localhost';
    my $dbuser = $conf->get('mysql.MAIN_PROG_DBUSER')  || '';
    my $dbpass = $conf->get('mysql.MAIN_PROG_DBPASS')  || '';
    my $dbport = $conf->get('mysql.MAIN_PROG_DBPORT')  || 3306;
    my $mode   = $self->{charset_mode} // 'utf8mb4';

    # DBD::MariaDB refuses port when host=localhost (uses Unix socket instead)
    # Force TCP by converting localhost to 127.0.0.1
    my $tcp_host = ($dbhost eq 'localhost') ? '127.0.0.1' : $dbhost;
    my $dsn = "DBI:MariaDB:database=$dbname;host=$tcp_host;port=$dbport";
    my %attrs = (
        RaiseError           => 0,
        PrintError           => 0,
        AutoCommit           => 1,
        mariadb_auto_reconnect => 1,
    );

    $logger->log(1, "Connecting to DB: $dbname at $dbhost:$dbport (charset_mode=$mode)");
    my $dbh = DBI->connect($dsn, $dbuser, $dbpass, \%attrs);
    unless ($dbh) {
        $logger->log(0, "DBI connect failed: $DBI::errstr");
        return;
    }

    _apply_session_charset($dbh, $logger, $mode);
    $self->{dbh} = $dbh;
}

sub dbh {
    my ($self) = @_;
    return $self->{dbh};
}

# ensure_connected() — verify DB handle is alive, reconnect if needed
# Call this before any critical DB operation in long-running event loops
sub ensure_connected {
    my ($self) = @_;
    my $dbh = $self->{dbh};

    # Quick path: handle exists and ping succeeds
    return $dbh if $dbh && eval { $dbh->ping };

 $self->{logger}->log(1, "DB connection lost reconnecting...") if $self->{logger};
    $self->_connect;
    return $self->{dbh};
}

1;
