<?php

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

use App\Http\Requests\Api\Admin\V1\ClienteRequest;
use App\Http\Resources\Admin\V1\ClientResource;
use App\Models\Clients\Client;
use Illuminate\Database\UniqueConstraintViolationException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;

/**
 * Buscar, crear y editar clientes. **No se borra ni se da de baja**: eso corta el servicio
 * de todos sus sitios y se hace desde el panel.
 */
class ClientesController extends ControladorDeAdministracion
{
    /**
     * `shortname`, `crm_id` y `cif` exactos; `name` contiene. El `cif` se puede buscar
     * aunque no se devuelva: sirve para encontrar al cliente, no hace falta enseñarlo.
     */
    public function index(Request $request): AnonymousResourceCollection
    {
        $porPagina = $this->validarListado($request, [
            'shortname' => 'nullable|string|max:50',
            'crm_id' => 'nullable|string|max:100',
            'cif' => 'nullable|string|max:20',
            'name' => 'nullable|string|max:200',
        ]);

        $clientes = Client::query()
            ->when($request->filled('shortname'), fn ($q) => $q->where('shortname', $request->query('shortname')))
            ->when($request->filled('crm_id'), fn ($q) => $q->where('crm_id', $request->query('crm_id')))
            ->when($request->filled('cif'), fn ($q) => $q->where('cif', $request->query('cif')))
            ->when($request->filled('name'), fn ($q) => $q->where('name', 'like', '%' . $request->query('name') . '%'))
            ->orderBy('id')
            ->paginate($porPagina)
            ->withQueryString();

        return ClientResource::collection($clientes);
    }

    public function show(Client $client): ClientResource
    {
        return ClientResource::make($client);
    }

    public function store(ClienteRequest $request): JsonResponse
    {
        $datos = $request->datos();

        try {
            $cliente = Client::create([...$datos, 'actived' => true]);
        } catch (UniqueConstraintViolationException) {
            // Dos altas iguales a la vez pasan las dos la comprobación previa, y la segunda
            // choca con el índice único. Es el mismo caso que un duplicado: 409 con el que
            // ganó, no un 500 con el SQL (auditoría PRODSECU-215).
            $existente = Client::query()
                ->where('shortname', $datos['shortname'] ?? null)
                ->when(! empty($datos['crm_id']), fn ($q) => $q->orWhere('crm_id', $datos['crm_id']))
                ->first();

            return response()->json(array_filter([
                'message' => 'Ya existe un cliente con ese shortname o crm_id.',
                'data' => $existente ? ClientResource::make($existente)->resolve($request) : null,
            ]), 409);
        }

        $this->rastro(
            $request,
            'Cliente ' . $cliente->name . ' (' . $cliente->shortname . ') creado desde la API de administración',
            'Client',
            $cliente->id
        );

        return ClientResource::make($cliente)->response()->setStatusCode(201);
    }

    public function update(ClienteRequest $request, Client $client): ClientResource
    {
        $client->fill($request->datos());
        $cambios = array_keys($client->getDirty());

        if ($cambios !== []) {
            $client->save();

            $this->rastro(
                $request,
                'Cliente ' . $client->name . ' editado desde la API de administración: ' . implode(', ', $cambios),
                'Client',
                $client->id
            );
        }

        return ClientResource::make($client);
    }
}
