<?php
namespace App\Services;

use PDO;

/** Applies ordered *.sql files from a migrations dir, tracked in a `migrations` table. */
class Migrator
{
    private PDO $pdo;
    private string $dir;

    public function __construct(PDO $pdo, string $dir)
    {
        $this->pdo = $pdo;
        $this->dir = $dir;
    }

    public function ensureTable(): void
    {
        $this->pdo->exec(
            "CREATE TABLE IF NOT EXISTS `migrations` (
                `id` INT AUTO_INCREMENT PRIMARY KEY,
                `filename` VARCHAR(255) NOT NULL UNIQUE,
                `applied_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"
        );
    }

    /** @return string[] filenames already applied */
    public function applied(): array
    {
        return $this->pdo->query("SELECT filename FROM `migrations`")->fetchAll(PDO::FETCH_COLUMN) ?: [];
    }

    /** @return string[] absolute paths of pending migrations, in order */
    public function pending(): array
    {
        $all = glob($this->dir . '/*.sql') ?: [];
        sort($all);
        $applied = $this->applied();
        return array_values(array_filter($all, fn($p) => !in_array(basename($p), $applied, true)));
    }

    /** @return string[] filenames applied this run */
    public function migrate(): array
    {
        $this->ensureTable();
        $done = [];
        foreach ($this->pending() as $path) {
            $this->pdo->exec((string) file_get_contents($path));
            $stmt = $this->pdo->prepare("INSERT IGNORE INTO `migrations` (filename) VALUES (?)");
            $stmt->execute([basename($path)]);
            $done[] = basename($path);
        }
        return $done;
    }
}
