<?php

namespace App\Http\Requests\Admin;

use App\Services\Lubricantes\LubricanteCatalogService;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Validator;

class LubricanteIndexRequest extends FormRequest
{
    private const DEFAULT_PAGE_SIZE = 10;
    private const DEFAULT_PAGE_NUMBER = 1;
    private const MAX_PAGE_SIZE = 100;

    /**
     * La autorización real vive en los middlewares `auth:sanctum`,
     * `abilities:admin`, `uuid-check` y `rootUser`; aquí sólo declaramos que el
     * request puede validarse cuando ya superó esa barrera.
     */
    public function authorize(): bool
    {
        return true;
    }

    /**
     * Restringe paginación, filtros y orden para evitar queries arbitrarias
     * sobre columnas no soportadas por la grilla administrativa.
     *
     * @return array<string, mixed>
     */
    public function rules(): array
    {
        return [
            'page' => ['nullable', 'array'],
            'page.size' => ['nullable', 'integer', 'min:1', 'max:' . self::MAX_PAGE_SIZE],
            'page.number' => ['nullable', 'integer', 'min:1'],
            'sort' => ['nullable', 'string', 'max:80'],
            'filter' => ['nullable', 'array'],
            'filter.id' => ['nullable', 'integer', 'min:1'],
            'filter.titulo' => ['nullable', 'string', 'max:120'],
            'filter.estado' => ['nullable', Rule::in([0, 1, '0', '1'])],
        ];
    }

    /**
     * Rechaza filtros y sorts desconocidos. Las reglas nativas validan valores,
     * pero este paso bloquea claves extra para no dejar superficie de consulta
     * accidental en futuras modificaciones del controller.
     */
    public function withValidator(Validator $validator): void
    {
        $validator->after(function (Validator $validator): void {
            $this->validateFilterKeys($validator);
            $this->validateSortFields($validator);
        });
    }

    /**
     * Tamaño de página validado y acotado defensivamente.
     */
    public function pageSize(): int
    {
        return (int) $this->input('page.size', self::DEFAULT_PAGE_SIZE);
    }

    /**
     * Número de página validado para evitar offsets negativos o ambiguos.
     */
    public function pageNumber(): int
    {
        return (int) $this->input('page.number', self::DEFAULT_PAGE_NUMBER);
    }

    /**
     * Orden pedido por la grilla. La whitelist definitiva se aplica en el
     * servicio porque allí vive el contrato de consulta.
     */
    public function sort(): ?string
    {
        return $this->filled('sort') ? (string) $this->input('sort') : null;
    }

    /**
     * Filtros ya validados; se eliminan claves vacías para no degradar el plan
     * de consulta con condiciones sin efecto.
     *
     * @return array<string, mixed>
     */
    public function filters(): array
    {
        return collect($this->input('filter', []))
            ->reject(fn ($value) => $value === null || $value === '')
            ->all();
    }

    /**
     * @param Validator $validator
     */
    private function validateFilterKeys(Validator $validator): void
    {
        foreach (array_keys($this->input('filter', [])) as $filter) {
            if (!in_array($filter, LubricanteCatalogService::FILTERABLE_COLUMNS, true)) {
                $validator->errors()->add('filter.' . $filter, 'El filtro indicado no está soportado.');
            }
        }
    }

    /**
     * @param Validator $validator
     */
    private function validateSortFields(Validator $validator): void
    {
        $sort = $this->input('sort');

        if (!$sort) {
            return;
        }

        foreach (explode(',', (string) $sort) as $sortField) {
            $column = ltrim(trim($sortField), '-');

            if (!in_array($column, LubricanteCatalogService::SORTABLE_COLUMNS, true)) {
                $validator->errors()->add('sort', 'El orden indicado no está soportado.');
            }
        }
    }
}
