<?php

namespace App\Services\Install;

use RuntimeException;

final class EnvironmentFileWriter
{
    public static function ensureFromExample(): void
    {
        $env = base_path('.env');
        $example = base_path('.env.example');

        if (! is_file($env) && is_file($example)) {
            if (! @copy($example, $env)) {
                throw new RuntimeException('Could not copy .env.example to .env. Create .env manually on the server.');
            }
        }

        if (! is_file($env)) {
            throw new RuntimeException('.env is missing. Copy .env.example to .env (via SSH or cPanel File Manager), then reload this page.');
        }

        if (! is_writable($env)) {
            throw new RuntimeException('.env is not writable by the web server. Adjust permissions or edit .env manually.');
        }
    }

    /**
     * @param  array<string, string|bool|int|float|null>  $pairs
     */
    public static function setMany(array $pairs): void
    {
        $path = base_path('.env');
        $content = file_get_contents($path);
        if ($content === false) {
            throw new RuntimeException('Could not read .env.');
        }

        foreach ($pairs as $key => $value) {
            $content = self::setLine($content, $key, $value);
        }

        if (file_put_contents($path, $content) === false) {
            throw new RuntimeException('Could not write .env.');
        }
    }

    /**
     * @param  string|bool|int|float|null  $value
     */
    private static function setLine(string $content, string $key, $value): string
    {
        $formatted = self::formatValue($value);
        $pattern = '/^'.preg_quote($key, '/').'=.*/m';
        if (preg_match($pattern, $content)) {
            return (string) preg_replace($pattern, "{$key}={$formatted}", $content);
        }

        return rtrim($content)."\n{$key}={$formatted}\n";
    }

    /**
     * @param  string|bool|int|float|null  $value
     */
    private static function formatValue($value): string
    {
        if (is_bool($value)) {
            return $value ? 'true' : 'false';
        }
        if (is_int($value) || is_float($value)) {
            return (string) $value;
        }
        if ($value === null) {
            return '""';
        }

        $s = (string) $value;
        if ($s === '' || preg_match('/[\s#"\'\\\\$=]/', $s)) {
            return '"'.str_replace(['\\', '"'], ['\\\\', '\\"'], $s).'"';
        }

        return $s;
    }
}
