<?php

namespace Modules\Shared\Support;

use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;

/**
 * Writes KEY=VALUE pairs directly into the .env file, preserving every
 * other line untouched — backs the Access group's "App Settings" page
 * (Filament), which edits real env-backed config values (config('app.*'),
 * config('booking.*')) in place rather than introducing a parallel
 * DB-backed settings table. Existing keys are replaced in place; missing
 * keys are appended.
 *
 * Requires the .env file to be writable by the web server process — not
 * guaranteed on every deployment target (e.g. an immutable/read-only
 * container filesystem). Callers should surface a clear error if the write
 * fails rather than silently losing the change.
 */
class EnvFileWriter
{
    private readonly string $path;

    public function __construct(?string $path = null)
    {
        $this->path = $path ?? base_path('.env');
    }

    /**
     * @param  array<string, bool|int|string|null>  $values
     */
    public function write(array $values): void
    {
        $contents = File::exists($this->path) ? File::get($this->path) : '';

        foreach ($values as $key => $value) {
            $contents = $this->setKey($contents, $key, $value);
        }

        File::put($this->path, $contents);
    }

    private function setKey(string $contents, string $key, bool|int|string|null $value): string
    {
        $line = $key.'='.$this->formatValue($value);
        $pattern = '/^'.preg_quote($key, '/').'=.*$/m';

        if (preg_match($pattern, $contents) === 1) {
            return (string) preg_replace($pattern, $line, $contents, 1);
        }

        return rtrim($contents, "\n")."\n".$line."\n";
    }

    private function formatValue(bool|int|string|null $value): string
    {
        if (is_bool($value)) {
            return $value ? 'true' : 'false';
        }

        if ($value === null || $value === '') {
            return '';
        }

        if (is_int($value)) {
            return (string) $value;
        }

        // Quote values containing whitespace or characters that would
        // otherwise break .env parsing (matches the convention already used
        // by hand-written entries in this project's .env.example).
        return Str::contains($value, [' ', '#', '"'])
            ? '"'.str_replace('"', '\\"', $value).'"'
            : $value;
    }
}
