<?php

declare(strict_types=1);

function dev_required_env(string $name): string
{
    $value = getenv($name);
    if ($value === false || trim($value) === '') {
        fwrite(STDERR, "Missing environment variable: {$name}\n");
        exit(1);
    }

    return $value;
}

function dev_pdo(): PDO
{
    $dsn = sprintf(
        'mysql:host=%s;port=%s;dbname=%s;charset=utf8mb4',
        dev_required_env('DB_HOST'),
        getenv('DB_PORT') ?: '3306',
        dev_required_env('DB_NAME')
    );

    return new PDO($dsn, dev_required_env('DB_USER'), dev_required_env('DB_PASS'), [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_EMULATE_PREPARES => true,
    ]);
}

function dev_apply_schema(PDO $pdo): void
{
    dev_apply_migrations($pdo);
}

function dev_migrations_dir(): string
{
    return __DIR__ . '/../database/migrations';
}

function dev_ensure_migration_table(PDO $pdo): void
{
    $pdo->exec(
        'CREATE TABLE IF NOT EXISTS schema_migrations (
            version VARCHAR(255) PRIMARY KEY,
            applied_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci'
    );
}

/**
 * @return array<string, true>
 */
function dev_applied_migrations(PDO $pdo): array
{
    dev_ensure_migration_table($pdo);

    $applied = [];
    $stmt = $pdo->query('SELECT version FROM schema_migrations ORDER BY version');
    foreach ($stmt->fetchAll(PDO::FETCH_COLUMN) as $version) {
        $applied[(string)$version] = true;
    }

    return $applied;
}

/**
 * @return list<string> Applied migration filenames.
 */
function dev_apply_migrations(PDO $pdo): array
{
    $dir = dev_migrations_dir();
    $files = glob($dir . '/*.sql');
    if ($files === false || $files === []) {
        fwrite(STDERR, "No migration files found in {$dir}.\n");
        exit(1);
    }

    sort($files, SORT_STRING);
    $applied = dev_applied_migrations($pdo);
    $newlyApplied = [];
    $insert = $pdo->prepare('INSERT INTO schema_migrations (version) VALUES (?)');

    foreach ($files as $file) {
        $version = basename($file);
        if (isset($applied[$version])) {
            continue;
        }

        $sql = file_get_contents($file);
        if ($sql === false) {
            fwrite(STDERR, "Could not read migration file {$version}.\n");
            exit(1);
        }

        try {
            $pdo->exec($sql);
            $insert->execute([$version]);
            $newlyApplied[] = $version;
        } catch (Throwable $e) {
            fwrite(STDERR, "Migration {$version} failed: {$e->getMessage()}\n");
            exit(1);
        }
    }

    return $newlyApplied;
}
