<?php

declare(strict_types=1);

namespace Builder\Core\Http\Controllers\Settings;

use Builder\Core\Foundation\Registry;
use Builder\Core\Foundation\Settings\BuilderSettings;
use Builder\Core\Foundation\Settings\SettingsDefinition;
use Builder\Core\Http\Requests\Settings\UpdateSettingsRequest;
use Illuminate\Http\RedirectResponse;

final class UpdateSettingsController
{
    public function __construct(private readonly Registry $registry) {}

    public function __invoke(UpdateSettingsRequest $request): RedirectResponse
    {
        $page = (string) $request->route('page', '');
        $parent = $request->route('parent') !== null ? (string) $request->route('parent') : null;
        $key = $parent !== null ? "{$parent}.{$page}" : $page;
        $definition = $this->registry->resolveSettingsPage($key);

        /** @var SettingsDefinition $definition Guaranteed non-null: FormRequest::authorize() aborts 404 first. */
        $data = $definition->getRules()
            ? $request->validated()
            : $request->except(['_token', '_method']);

        $this->saveToClass($definition->getSettingsClass(), $data);

        foreach ($definition->getExtensions() as $extension) {
            $extClass = $extension::getSettingsClass();
            $extData = array_intersect_key($data, array_flip(app($extClass)->propertyNames()));

            if (! empty($extData)) {
                $this->saveToClass($extClass, $extData);
            }
        }

        return back()->with('success', __('builder::builder.settings.saved', ['page' => $definition->getPage()->getLabel()]));
    }

    /**
     * @param  class-string<BuilderSettings>  $class
     * @param  array<string, mixed>  $data
     */
    private function saveToClass(string $class, array $data): void
    {
        (new $class)->seedDefaults();

        $data = $class::coerceData($data);

        $settings = app($class);
        $settings->fill($data);
        $settings->save();
    }
}
