<?php

namespace App\Support;

class InstallBootstrap
{
    public static function prepare(string $basePath, ?string $requestUri = null, ?string $scriptName = null): void
    {
        $redirectPath = static::installRedirectPathIfNeeded($basePath, $requestUri, $scriptName);

        if ($redirectPath !== null) {
            static::redirectToInstaller($redirectPath);
        }

        if (! static::isInstallRequest($requestUri)) {
            return;
        }

        static::disableConfigCache($basePath);
        static::forceInstallerRuntimeSettings();

        if (static::hasAppKeyConfigured($basePath)) {
            return;
        }

        $temporaryKey = static::temporaryAppKey($basePath);

        static::setEnvironmentValue('APP_KEY', $temporaryKey);
        static::setEnvironmentValue('INSTALLER_TEMP_APP_KEY', '1');
    }

    public static function installRedirectPathIfNeeded(string $basePath, ?string $requestUri = null, ?string $scriptName = null): ?string
    {
        if (static::isInstallRequest($requestUri) || static::hasAppKeyConfigured($basePath)) {
            return null;
        }

        return static::installPathFromScriptName($scriptName);
    }

    protected static function isInstallRequest(?string $requestUri): bool
    {
        $path = parse_url($requestUri ?? '/', PHP_URL_PATH);
        $path = '/' . trim((string) $path, '/');

        return (bool) preg_match('~(?:^|/)install$~i', $path);
    }

    protected static function disableConfigCache(string $basePath): void
    {
        $temporaryConfigCache = rtrim($basePath, '/\\') . DIRECTORY_SEPARATOR . 'bootstrap' . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'install-config.php';

        static::setEnvironmentValue('APP_CONFIG_CACHE', $temporaryConfigCache);
    }

    protected static function forceInstallerRuntimeSettings(): void
    {
        static::setEnvironmentValue('SESSION_DRIVER', 'file');
        static::setEnvironmentValue('CACHE_STORE', 'file');
        static::setEnvironmentValue('QUEUE_CONNECTION', 'sync');
    }

    protected static function hasAppKeyConfigured(string $basePath): bool
    {
        $runtimeKey = $_ENV['APP_KEY'] ?? $_SERVER['APP_KEY'] ?? getenv('APP_KEY') ?: null;

        if (is_string($runtimeKey) && trim($runtimeKey) !== '') {
            return true;
        }

        $environmentPath = rtrim($basePath, '/\\') . DIRECTORY_SEPARATOR . '.env';

        if (! is_file($environmentPath)) {
            return false;
        }

        foreach (file($environmentPath, FILE_IGNORE_NEW_LINES) ?: [] as $line) {
            $trimmed = trim($line);

            if ($trimmed === '' || str_starts_with($trimmed, '#') || ! str_contains($trimmed, '=')) {
                continue;
            }

            [$key, $value] = explode('=', $line, 2);

            if (trim($key) !== 'APP_KEY') {
                continue;
            }

            $value = trim($value);

            if ($value !== '' && (
                (str_starts_with($value, '"') && str_ends_with($value, '"'))
                || (str_starts_with($value, "'") && str_ends_with($value, "'"))
            )) {
                $value = substr($value, 1, -1);
            }

            return trim($value) !== '';
        }

        return false;
    }

    protected static function setEnvironmentValue(string $key, string $value): void
    {
        putenv($key . '=' . $value);
        $_ENV[$key] = $value;
        $_SERVER[$key] = $value;
    }

    protected static function temporaryAppKey(string $basePath): string
    {
        $path = static::temporaryAppKeyPath($basePath);

        if (is_file($path)) {
            $existing = trim((string) file_get_contents($path));

            if (str_starts_with($existing, 'base64:') && $existing !== '') {
                return $existing;
            }
        }

        $key = 'base64:' . base64_encode(random_bytes(32));
        $directory = dirname($path);

        if (! is_dir($directory)) {
            @mkdir($directory, 0775, true);
        }

        if (@file_put_contents($path, $key) !== false) {
            return $key;
        }

        return 'base64:' . base64_encode(hash('sha256', $basePath, true));
    }

    protected static function temporaryAppKeyPath(string $basePath): string
    {
        return rtrim($basePath, '/\\') . DIRECTORY_SEPARATOR . 'bootstrap' . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'install-app.key';
    }

    protected static function installPathFromScriptName(?string $scriptName): string
    {
        $directory = trim(str_replace('\\', '/', dirname($scriptName ?? '/index.php')), '/.');

        if ($directory === '') {
            return '/install';
        }

        return '/' . $directory . '/install';
    }

    protected static function redirectToInstaller(string $path): never
    {
        if (! headers_sent()) {
            header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
            header('Location: ' . $path, true, 302);
        }

        exit;
    }
}
