<?php

/**
 * Classe abstraite de base pour tous les migrators
 *
 * Fournit les méthodes communes pour migrer des données d'une table
 */
abstract class DataMigrator
{
    protected $connection;
    protected $logger;
    protected $sourceDb;
    protected $targetDb;

    /**
     * Constructeur
     *
     * @param DatabaseConnection $connection Connexion aux bases
     * @param MigrationLogger $logger Logger
     */
    public function __construct(DatabaseConnection $connection, MigrationLogger $logger)
    {
        $this->connection = $connection;
        $this->logger = $logger;
        $this->sourceDb = $connection->getSourceDb();
        $this->targetDb = $connection->getTargetDb();
    }

    /**
     * Méthode principale de migration (à implémenter dans chaque migrator)
     *
     * @param int|null $entityId ID de l'entité à migrer (null = toutes)
     * @param bool $deleteBefore Supprimer les données existantes avant migration
     * @return array ['success' => int, 'errors' => int]
     */
    abstract public function migrate(?int $entityId = null, bool $deleteBefore = false): array;

    /**
     * Retourne le nom de la table gérée par ce migrator
     */
    abstract public function getTableName(): string;

    /**
     * Supprime les données d'une entité dans la cible
     * À surcharger si la logique de suppression est spécifique
     *
     * @param int $entityId ID de l'entité
     * @return int Nombre de lignes supprimées
     */
    protected function deleteEntityData(int $entityId): int
    {
        $table = $this->getTableName();

        try {
            // Par défaut: suppression simple avec fk_entite
            $stmt = $this->targetDb->prepare("DELETE FROM $table WHERE fk_entite = ?");
            $stmt->execute([$entityId]);
            $deleted = $stmt->rowCount();

            if ($deleted > 0) {
                $this->logger->debug("  Supprimé $deleted ligne(s) de $table pour entité #$entityId");
            }

            return $deleted;

        } catch (PDOException $e) {
            $this->logger->warning("  Erreur suppression $table: " . $e->getMessage());
            return 0;
        }
    }

    /**
     * Compte les lignes dans la source
     *
     * @param int|null $entityId ID de l'entité (null = toutes)
     * @return int Nombre de lignes
     */
    protected function countSourceRows(?int $entityId = null): int
    {
        return $this->connection->countSourceRows($this->getTableName(), $entityId);
    }

    /**
     * Compte les lignes dans la cible
     *
     * @param int|null $entityId ID de l'entité (null = toutes)
     * @return int Nombre de lignes
     */
    protected function countTargetRows(?int $entityId = null): int
    {
        return $this->connection->countTargetRows($this->getTableName(), $entityId);
    }

    /**
     * Log le début de la migration d'une table
     */
    protected function logStart(?int $entityId = null): void
    {
        $table = $this->getTableName();
        $entityStr = $entityId ? " pour entité #$entityId" : " (toutes les entités)";
        $this->logger->info("🔄 Migration de $table{$entityStr}...");
    }

    /**
     * Log la fin de la migration avec statistiques
     *
     * @param int $success Nombre de succès
     * @param int $errors Nombre d'erreurs
     * @param int|null $entityId ID de l'entité
     */
    protected function logEnd(int $success, int $errors, ?int $entityId = null): void
    {
        $table = $this->getTableName();
        $sourceCount = $this->countSourceRows($entityId);
        $targetCount = $this->countTargetRows($entityId);
        $diff = $targetCount - $sourceCount;
        $diffStr = $diff >= 0 ? "+$diff" : "$diff";

        if ($errors > 0) {
            $this->logger->warning("  ⚠️  $table: $success succès, $errors erreurs");
        } else {
            $this->logger->success("  ✓ $table: $success enregistrement(s) migré(s)");
        }

        $this->logger->info("  📊 SOURCE: $sourceCount → CIBLE: $targetCount (différence: $diffStr)");
    }

    /**
     * Exécute une requête INSERT avec ON DUPLICATE KEY UPDATE
     *
     * @param string $insertSql SQL d'insertion
     * @param array $data Données à insérer
     * @return bool True si succès
     */
    protected function insertOrUpdate(string $insertSql, array $data): bool
    {
        try {
            $stmt = $this->targetDb->prepare($insertSql);
            $stmt->execute($data);
            return true;
        } catch (PDOException $e) {
            $this->logger->debug("  Erreur INSERT: " . $e->getMessage());
            return false;
        }
    }

    /**
     * Démarre une transaction sur la cible
     */
    protected function beginTransaction(): void
    {
        if (!$this->targetDb->inTransaction()) {
            $this->targetDb->beginTransaction();
        }
    }

    /**
     * Commit la transaction
     */
    protected function commit(): void
    {
        if ($this->targetDb->inTransaction()) {
            $this->targetDb->commit();
        }
    }

    /**
     * Rollback la transaction
     */
    protected function rollback(): void
    {
        if ($this->targetDb->inTransaction()) {
            $this->targetDb->rollBack();
        }
    }
}
