<?php

declare(strict_types=1);

namespace App\Http\Requests\Setting;

use Illuminate\Foundation\Http\FormRequest;

/**
 * One request for the whole Settings screen — every tab posts to the same
 * `PUT /admin/settings`, since a master editing "Company" has no reason to
 * lose an in-progress edit to "Notifications" made on the same page.
 *
 * `master` middleware already guards the whole `/admin` prefix; there is no
 * per-field authorization here, matching how Settings has no policy class —
 * see architecture §11.
 */
class UpdateSettingsRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    /**
     * @return array<string, mixed>
     */
    public function rules(): array
    {
        return [
            // Company
            'company_name' => ['required', 'string', 'max:150'],
            'company_logo' => ['nullable', 'file', 'mimes:png,jpg,jpeg,svg', 'max:2048'],
            'remove_company_logo' => ['nullable', 'boolean'],
            'company_address' => ['nullable', 'string', 'max:500'],
            'contact_email' => ['nullable', 'email', 'max:150'],
            'contact_phone' => ['nullable', 'string', 'max:30'],

            // General
            'application_name' => ['required', 'string', 'max:100'],
            'date_format' => ['required', 'string', 'max:30'],
            'datetime_format' => ['required', 'string', 'max:30'],
            'timezone' => ['required', 'timezone'],
            'default_currency' => ['required', 'string', 'size:3', 'alpha'],
            'pagination_per_page' => ['required', 'integer', 'min:10', 'max:200'],

            // Assets
            'asset_tag_prefix' => ['required', 'string', 'max:10', 'regex:/^[A-Z0-9]+$/'],
            'asset_tag_scope' => ['required', 'in:per_category,global'],
            'asset_tag_sequence_padding' => ['required', 'integer', 'min:3', 'max:8'],
            'import_max_rows' => ['required', 'integer', 'min:100', 'max:10000'],

            // Notifications
            'enable_warranty_emails' => ['nullable', 'boolean'],
            'warranty_alert_days' => ['required', 'string', 'max:100', 'regex:/^\s*\d+\s*(,\s*\d+\s*)*$/'],
            'warranty_alert_recipients' => ['nullable', 'string', 'max:1000'],
            'mail_from_name' => ['nullable', 'string', 'max:100'],
            'mail_from_address' => ['nullable', 'email', 'max:150'],

            // Security
            'password_min_length' => ['required', 'integer', 'min:10', 'max:32'],
            'audit_retention_months' => ['required', 'integer', 'min:1', 'max:120'],
        ];
    }

    /**
     * @return array<string, string>
     */
    public function attributes(): array
    {
        return [
            'warranty_alert_days' => 'warranty alert windows',
            'warranty_alert_recipients' => 'warranty alert recipients',
        ];
    }

    protected function prepareForValidation(): void
    {
        // Blank optional fields must reach the controller as null, not '' —
        // AppSettings::set() would otherwise store an empty string that
        // reads as "set" everywhere a truthy check like `if ($value)` is
        // used to decide whether the setting is configured at all (the mail
        // "from" override and the company contact fields both do this).
        $nullable = [
            'company_address', 'contact_email', 'contact_phone',
            'mail_from_name', 'mail_from_address', 'warranty_alert_recipients',
        ];

        $this->merge(collect($nullable)
            ->mapWithKeys(fn (string $key): array => [$key => $this->filled($key) ? $this->input($key) : null])
            ->all());
    }
}
