<?php

namespace MintyPHP\Service\Module;

use MintyPHP\App\Module\ModuleRegistry;
use MintyPHP\Repository\Module\ModuleMigrationRepository;
use MintyPHP\Support\SqlStatementParser;
use RuntimeException;

/**
 * Discovers and applies pending SQL migrations for all enabled modules.
 *
 * Orchestration only — SQL lives in ModuleMigrationRepository,
 * statement parsing in SqlStatementParser.
 */
final class ModuleMigrationService
{
    public function __construct(
        private readonly ModuleRegistry $registry,
        private readonly ModuleMigrationRepository $repository,
    ) {
    }

    /**
     * Apply all pending module migrations.
     *
     * @return array{ok: bool, applied: int, skipped_empty: int, modules_enabled: int}
     */
    public function applyPendingMigrations(): array
    {
        $modules = $this->registry->getModules();
        $modulesEnabled = count($modules);

        if ($modulesEnabled === 0) {
            return ['ok' => true, 'applied' => 0, 'skipped_empty' => 0, 'modules_enabled' => 0];
        }

        $this->repository->ensureTrackingTable();

        $totalApplied = 0;
        $skippedEmpty = 0;

        foreach ($modules as $manifest) {
            $migrationsPath = $manifest->migrationsPath;
            if ($migrationsPath === null || !is_dir($migrationsPath)) {
                continue;
            }

            $files = glob($migrationsPath . '/*.sql');
            if ($files === false || count($files) === 0) {
                continue;
            }
            sort($files);

            $applied = $this->repository->getAppliedFilenames((string) $manifest->id);

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

                $sql = file_get_contents($file);
                if ($sql === false || trim($sql) === '') {
                    $skippedEmpty++;
                    continue;
                }

                $this->repository->beginTransaction();
                try {
                    $statements = SqlStatementParser::splitStatements($sql);
                    foreach ($statements as $statement) {
                        $this->repository->executeStatement($statement);
                    }

                    $this->repository->recordApplied((string) $manifest->id, $filename);
                    $this->repository->commit();
                } catch (\Throwable $migrationError) {
                    $this->repository->rollback();
                    throw new RuntimeException(
                        sprintf("Migration %s/%s failed: %s", $manifest->id, $filename, $migrationError->getMessage()),
                        0,
                        $migrationError
                    );
                }

                $totalApplied++;
            }
        }

        return [
            'ok' => true,
            'applied' => $totalApplied,
            'skipped_empty' => $skippedEmpty,
            'modules_enabled' => $modulesEnabled,
        ];
    }
}
