<?php

namespace App\Http\Controllers\Api\Admin\V1;

use App\Http\Controllers\Controller;
use App\Models\Monitoring\Log;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

/**
 * Lo común a los controladores de la API de administración (`/api/admin/v1`, PRODSECU-215).
 */
abstract class ControladorDeAdministracion extends Controller
{
    /** Tamaño de página por defecto de los listados. */
    protected const POR_PAGINA = 25;

    /** El máximo que se puede pedir con `per_page`. */
    protected const POR_PAGINA_MAXIMO = 100;

    /**
     * Valida los filtros de un listado (más `page` y `per_page`) y devuelve el tamaño de
     * página. Un filtro mal escrito es un 422, no un listado vacío que parece correcto.
     *
     * @param  array<string, mixed>  $filtros
     */
    protected function validarListado(Request $request, array $filtros = []): int
    {
        $this->validarConsulta($request, $filtros + [
            // Con techo: una página de 19 cifras desbordaba el cálculo del desplazamiento y
            // daba un 500 con la traza (auditoría PRODSECU-215).
            'page' => 'nullable|integer|min:1|max:100000',
            'per_page' => 'nullable|integer|min:1|max:' . self::POR_PAGINA_MAXIMO,
        ]);

        return (int) $request->query('per_page', self::POR_PAGINA);
    }

    /** @param  array<string, mixed>  $reglas */
    protected function validarConsulta(Request $request, array $reglas): void
    {
        $validator = Validator::make($request->query(), $reglas, [
            'per_page.max' => 'per_page no puede pasar de ' . self::POR_PAGINA_MAXIMO . '.',
            'per_page.min' => 'per_page tiene que ser al menos 1.',
        ]);

        if ($validator->fails()) {
            $this->fallo('Los filtros no son válidos.', $validator->errors()->toArray(), 422);
        }
    }

    /**
     * Corta con `{message, errors}`. Para las reglas que dependen de más de un registro
     * —misma licencia y mismo cliente, compatibilidad de productos— y no caben en un
     * FormRequest.
     *
     * @param  array<string, list<string>>  $errores
     */
    protected function fallo(string $mensaje, array $errores = [], int $status = 422): never
    {
        $cuerpo = ['message' => $mensaje];

        if ($errores !== []) {
            $cuerpo['errors'] = $errores;
        }

        throw new HttpResponseException(new JsonResponse($cuerpo, $status));
    }

    /**
     * El rastro de cada alta o edición hecha por la API (16050).
     *
     * **Con el nombre del token**, que es lo único que dice quién fue: todos los tokens son
     * del mismo usuario de servicio, y «lo hizo el usuario de la API» no ayuda a nadie a
     * saber qué integración ha sido.
     */
    protected function rastro(Request $request, string $que, string $entidad, int $id): void
    {
        $token = $request->user()?->currentAccessToken();
        $nombre = $token?->name ?? 'desconocido';

        Log::db('info', '16050', $que . ' (token «' . $nombre . '»)', $entidad, (string) $id);
    }
}
