<?php

/**
 * Gestion des connexions PDO
 *
 * Crée et maintient les connexions aux bases source et cible
 */
class DatabaseConnection
{
    private $config;
    private $logger;
    private $sourceDb;
    private $targetDb;

    /**
     * Constructeur
     *
     * @param DatabaseConfig $config Configuration de l'environnement
     * @param MigrationLogger $logger Logger pour les messages
     */
    public function __construct(DatabaseConfig $config, MigrationLogger $logger)
    {
        $this->config = $config;
        $this->logger = $logger;
    }

    /**
     * Établit les connexions aux bases source et cible
     *
     * @return bool True si succès
     */
    public function connect(): bool
    {
        try {
            // Connexion à la base source
            $this->connectSource();

            // Connexion à la base cible
            $this->connectTarget();

            // Vérifier les versions MariaDB
            $this->checkVersions();

            return true;

        } catch (PDOException $e) {
            $this->logger->error("Erreur de connexion: " . $e->getMessage());
            return false;
        }
    }

    /**
     * Connexion à la base source
     */
    private function connectSource(): void
    {
        $dsn = sprintf(
            'mysql:host=%s;port=%d;dbname=%s;charset=utf8mb4',
            $this->config->getHost(),
            $this->config->getPort(),
            $this->config->getSourceDb()
        );

        $this->sourceDb = new PDO($dsn, $this->config->getUser(), $this->config->getPassword(), [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_TIMEOUT => 600,
            PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"
        ]);

        $this->logger->success("✓ Connexion SOURCE: {$this->config->getSourceDb()} sur {$this->config->getHost()}");
    }

    /**
     * Connexion à la base cible
     */
    private function connectTarget(): void
    {
        $dsn = sprintf(
            'mysql:host=%s;port=%d;dbname=%s;charset=utf8mb4',
            $this->config->getHost(),
            $this->config->getPort(),
            $this->config->getTargetDb()
        );

        $this->targetDb = new PDO($dsn, $this->config->getUser(), $this->config->getPassword(), [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_TIMEOUT => 600,
            PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"
        ]);

        $this->logger->success("✓ Connexion CIBLE: {$this->config->getTargetDb()} sur {$this->config->getHost()}");
    }

    /**
     * Vérifie et affiche les versions MariaDB
     */
    private function checkVersions(): void
    {
        $sourceVersion = $this->sourceDb->query("SELECT VERSION()")->fetchColumn();
        $targetVersion = $this->targetDb->query("SELECT VERSION()")->fetchColumn();

        $this->logger->info("  Version SOURCE: $sourceVersion");
        $this->logger->info("  Version CIBLE: $targetVersion");
    }

    /**
     * Retourne la connexion à la base source
     */
    public function getSourceDb(): PDO
    {
        if (!$this->sourceDb) {
            throw new Exception("Source database not connected. Call connect() first.");
        }
        return $this->sourceDb;
    }

    /**
     * Retourne la connexion à la base cible
     */
    public function getTargetDb(): PDO
    {
        if (!$this->targetDb) {
            throw new Exception("Target database not connected. Call connect() first.");
        }
        return $this->targetDb;
    }

    /**
     * Compte le nombre de lignes dans une table de la source
     *
     * @param string $table Nom de la table
     * @param int|null $entityId Filtrer par fk_entite (optionnel)
     * @return int Nombre de lignes
     */
    public function countSourceRows(string $table, ?int $entityId = null): int
    {
        $sql = "SELECT COUNT(*) FROM $table";

        if ($entityId !== null) {
            // Tables avec fk_entite direct
            if (in_array($table, ['users', 'operations', 'entites'])) {
                $sql .= " WHERE fk_entite = :entity_id";
            }
            // Tables liées via operations
            elseif (in_array($table, ['ope_sectors', 'ope_users', 'ope_pass'])) {
                $sql .= " WHERE fk_operation IN (SELECT id FROM operations WHERE fk_entite = :entity_id)";
            }
        }

        $stmt = $this->sourceDb->prepare($sql);
        if ($entityId !== null) {
            $stmt->execute(['entity_id' => $entityId]);
        } else {
            $stmt->execute();
        }

        return (int) $stmt->fetchColumn();
    }

    /**
     * Compte le nombre de lignes dans une table de la cible
     *
     * @param string $table Nom de la table
     * @param int|null $entityId Filtrer par fk_entite (optionnel)
     * @return int Nombre de lignes
     */
    public function countTargetRows(string $table, ?int $entityId = null): int
    {
        $sql = "SELECT COUNT(*) FROM $table";

        if ($entityId !== null) {
            if (in_array($table, ['users', 'operations', 'entites'])) {
                $sql .= " WHERE fk_entite = :entity_id";
            }
            elseif (in_array($table, ['ope_sectors', 'ope_users', 'ope_pass'])) {
                $sql .= " WHERE fk_operation IN (SELECT id FROM operations WHERE fk_entite = :entity_id)";
            }
        }

        $stmt = $this->targetDb->prepare($sql);
        if ($entityId !== null) {
            $stmt->execute(['entity_id' => $entityId]);
        } else {
            $stmt->execute();
        }

        return (int) $stmt->fetchColumn();
    }

    /**
     * Ferme les connexions
     */
    public function close(): void
    {
        $this->sourceDb = null;
        $this->targetDb = null;
        $this->logger->info("Connexions fermées");
    }
}
