<?php

declare(strict_types=1);

final class InstallationService
{
    public static function runtimeChecks(bool $withFilesystem = true): array
    {
        $checks = [];
        self::add($checks, 'php', version_compare(PHP_VERSION, '8.1.0', '>='), 'required', 'PHP 8.1+', PHP_VERSION);
        self::add(
            $checks,
            'pdo',
            extension_loaded('pdo'),
            'required',
            'PDO',
            extension_loaded('pdo') ? 'Disponible' : 'Extension absente',
        );
        self::add(
            $checks,
            'sqlite',
            extension_loaded('pdo_sqlite'),
            'required',
            'PDO SQLite',
            extension_loaded('pdo_sqlite') ? 'Disponible' : 'Installez l’extension PHP SQLite',
        );
        foreach (
            ['mbstring' => 'mbstring', 'json' => 'JSON', 'fileinfo' => 'Fileinfo', 'session' => 'Sessions']
            as $extension => $label
        ) {
            self::add(
                $checks,
                $extension,
                extension_loaded($extension),
                'required',
                $label,
                extension_loaded($extension) ? 'Disponible' : 'Extension absente',
            );
        }
        self::add(
            $checks,
            'zip',
            class_exists('ZipArchive'),
            'recommended',
            'ZIP',
            class_exists('ZipArchive')
                ? 'Sauvegardes ZIP disponibles'
                : 'Extension ZIP absente : sauvegardes indisponibles',
        );
        self::add(
            $checks,
            'curl',
            extension_loaded('curl'),
            'recommended',
            'cURL',
            extension_loaded('curl')
                ? 'Connecteurs externes disponibles'
                : 'Extension cURL absente : I-CAD et géocodage indisponibles',
        );
        self::add(
            $checks,
            'image',
            extension_loaded('imagick') || extension_loaded('gd'),
            'recommended',
            'Traitement des images',
            extension_loaded('imagick')
                ? 'ImageMagick disponible'
                : (extension_loaded('gd')
                    ? 'GD disponible'
                    : 'ImageMagick ou GD conseillé'),
        );
        if ($withFilesystem) {
            foreach (self::directories() as $key => $path) {
                if (!is_dir($path)) {
                    @mkdir($path, 0775, true);
                }
                self::add(
                    $checks,
                    'dir_' . $key,
                    is_dir($path) && is_writable($path),
                    'required',
                    'Écriture · ' . self::relative($path),
                    is_dir($path) && is_writable($path) ? 'Accessible en écriture' : 'Droits d’écriture insuffisants',
                );
            }
        }
        return $checks;
    }
    public static function blockingRuntimeIssues(): array
    {
        return array_values(
            array_filter(
                self::runtimeChecks(true),
                static fn(array $c): bool => $c['level'] === 'required' && !$c['ok'],
            ),
        );
    }
    public static function canInstall(array $checks): bool
    {
        foreach ($checks as $check) {
            if ($check['level'] === 'required' && !$check['ok']) {
                return false;
            }
        }
        return true;
    }
    public static function publicPath(): string
    {
        return dirname(__DIR__, 2) . '/public';
    }
    public static function directories(): array
    {
        $root = dirname(__DIR__, 2);
        return [
            'data' => $root . '/data',
            'storage' => $root . '/storage',
            'logs' => $root . '/storage/logs',
            'backups' => $root . '/storage/backups',
            'media' => $root . '/public/media',
            'association' => $root . '/data/association',
        ];
    }
    private static function add(
        array &$checks,
        string $key,
        bool $ok,
        string $level,
        string $label,
        string $detail,
    ): void {
        $checks[] = ['key' => $key, 'ok' => $ok, 'level' => $level, 'label' => $label, 'detail' => $detail];
    }
    private static function relative(string $path): string
    {
        return ltrim(str_replace(dirname(__DIR__, 2), '', $path), '/');
    }
}
