<?php

namespace Acms\Services\Installer;

use Acms\Services\Update\Database\Schema;
use RuntimeException;
use Throwable;

/**
 * 初回インストール時にデータベーステーブルを作成するクラス
 *
 * `Acms\Services\Update\Database\Schema` を使って、
 * 現在の DB と YAML 定義の差分を比較し、不足しているテーブルだけを作成する。
 *
 * 旧 setup/install.php::Install_Step_4::business() のテーブル作成ロジックを
 * Services 層に抽出したもの。
 */
final class SchemaCreator
{
    /**
     * まだ存在しないテーブルを作成する。既に全て存在する場合は何もしない (冪等)。
     *
     * @return list<string> 実際に作成されたテーブル名 (prefix 込み)
     */
    public function create(): array
    {
        $dsn = dsn();

        try {
            $schema = new Schema($dsn);
        } catch (Throwable $e) {
            throw new RuntimeException(
                sprintf('Failed to load schema info: %s', $e->getMessage()),
                0,
                $e,
            );
        }

        $missingTables = $schema->compareTables();
        if (count($missingTables) === 0) {
            return [];
        }

        try {
            $schema->createTables($missingTables, $schema->indexDefine);
        } catch (Throwable $e) {
            throw new RuntimeException(
                sprintf('Failed to create tables: %s', $e->getMessage()),
                0,
                $e,
            );
        }

        // Schema::createTables() は失敗時に例外を投げるため、ここに到達した時点で
        // 全 missingTables が作成済みとみなしてよい。
        return array_values(array_map('strval', $missingTables));
    }

    /**
     * 定義 (yaml) に対応するテーブルが既に 1 つ以上存在するか
     * (= compareTables() の差分が全量より少なければ「一部は存在する」=作成されている扱い)
     */
    public function isCreated(): bool
    {
        try {
            $dsn = dsn();
            $schema = new Schema($dsn);
            $definedTables = $schema->listUp($schema->define);
            $missingTables = $schema->compareTables();
            // 定義テーブル全てが missing なら未初期化、1 つでも存在すれば初期化済み扱い
            return count($missingTables) < count($definedTables);
        } catch (Throwable) {
            return false;
        }
    }
}
