<?php

declare(strict_types=1);

final class Migrations
{
    public static function run(string $migrationsDir): void
    {
        $db = DB::pdo();
        $db->exec('CREATE TABLE IF NOT EXISTS _migrations (name TEXT PRIMARY KEY, applied_at TEXT NOT NULL);');

        $files = glob(rtrim($migrationsDir, '/') . '/*.sql') ?: [];
        sort($files);

        foreach ($files as $file) {
            $name = basename($file);

            $stmt = $db->prepare('SELECT 1 FROM _migrations WHERE name = :n');
            $stmt->execute([':n' => $name]);
            if ($stmt->fetchColumn()) {
                continue;
            }

            $sql = file_get_contents($file);
            if ($sql === false) {
                throw new RuntimeException("Cannot read migration: $name");
            }

            // Les toutes premières installations utilisaient déjà deleted_at avant
            // que cette colonne ne soit correctement inscrite dans une migration.
            if ($name === '025_animal_archive_and_trash.sql') {
                $columns = array_column($db->query('PRAGMA table_info(animals)')->fetchAll(PDO::FETCH_ASSOC), 'name');
                if (!in_array('deleted_at', $columns, true)) {
                    $db->exec('ALTER TABLE animals ADD COLUMN deleted_at TEXT');
                }
            }

            // Répare les bases créées par une candidate rc.3 incomplète, dans
            // laquelle les médias privés étaient utilisés avant d'être migrés.
            if ($name === '089_media_schema_repair.sql') {
                $columns = array_column(
                    $db->query('PRAGMA table_info(animal_photos)')->fetchAll(PDO::FETCH_ASSOC),
                    'name',
                );
                if (!in_array('is_public', $columns, true)) {
                    $db->exec('ALTER TABLE animal_photos ADD COLUMN is_public INTEGER NOT NULL DEFAULT 1');
                }
            }

            // Les anciennes bases possédaient déjà le nouvel historique alors
            // que les installations neuves recevaient encore son premier schéma.
            if ($name === '090_medication_administration_routes.sql') {
                $columns = array_column(
                    $db->query('PRAGMA table_info(animal_history)')->fetchAll(PDO::FETCH_ASSOC),
                    'name',
                );
                if (!in_array('type', $columns, true)) {
                    $db->exec("ALTER TABLE animal_history ADD COLUMN type TEXT NOT NULL DEFAULT 'history'");
                }
                if (!in_array('label', $columns, true)) {
                    $db->exec("ALTER TABLE animal_history ADD COLUMN label TEXT NOT NULL DEFAULT ''");
                }
                if (!in_array('details', $columns, true)) {
                    $db->exec('ALTER TABLE animal_history ADD COLUMN details TEXT');
                }
            }

            $db->beginTransaction();
            try {
                $db->exec($sql);
                $ins = $db->prepare("INSERT INTO _migrations(name, applied_at) VALUES(:n, datetime('now'))");
                $ins->execute([':n' => $name]);
                $db->commit();
            } catch (Throwable $e) {
                $db->rollBack();
                throw new RuntimeException('Migration ' . $name . ' : ' . $e->getMessage(), 0, $e);
            }
        }
    }
}
