<?php

namespace App\Http\Controllers;

use App\Jobs\ProcessPendingProviderNotifications;
use App\Models\NotificationMap;
use App\NotificationMaps\NotificationOpenApiGenerator;
use App\NotificationMaps\NotificationPayloadMapper;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Mtc\MercuryDataModels\PendingProviderNotification;

/**
 * Generic inbound notification endpoint. Resolves the active NotificationMap for the
 * requested slug, validates the payload against the map's rules (returning 422 on
 * failure), then captures the raw payload to the shared pending-notification drain
 * for asynchronous mapping + vehicle upsert.
 */
class NotificationMapController extends Controller
{
    public function __construct(private readonly NotificationPayloadMapper $mapper)
    {
    }

    public function store(Request $request, string $notificationSlug): JsonResponse
    {
        $map = NotificationMap::query()
            ->where('slug', $notificationSlug)
            ->where('active', true)
            ->first();

        // Unknown or inactive slug (and, defensively, reserved slugs that should never
        // reach here because their fixed routes match first) are not addressable.
        if (!$map || in_array($notificationSlug, NotificationMap::RESERVED_SLUGS, true)) {
            abort(404);
        }

        $payload = $request->all();

        // Validate synchronously so the caller gets an immediate 422 on a bad payload.
        // A ValidationException bubbles up to a 422 JSON response. The mapped result is
        // also used to derive the dedupe reference; the heavy upsert runs in the drain.
        $mapped = $this->mapper->map($map, $payload);

        $reference = $mapped->attributes['uuid']
            ?? $mapped->attributes['registration_number']
            ?? $mapped->attributes['vin']
            ?? null;

        PendingProviderNotification::capture($map->providerKey(), $reference, $payload);
        ProcessPendingProviderNotifications::dispatch($map->providerKey());

        return response()->json(['status' => 'received']);
    }

    /**
     * Serve the OpenAPI document describing this notification's inbound endpoint.
     * Resolves regardless of active state so integrators can read the spec before
     * the notification is switched on.
     */
    public function docs(string $notificationSlug): JsonResponse
    {
        $map = NotificationMap::query()->where('slug', $notificationSlug)->first();

        if (!$map || in_array($notificationSlug, NotificationMap::RESERVED_SLUGS, true)) {
            abort(404);
        }

        return response()->json(app(NotificationOpenApiGenerator::class)->generate($map));
    }
}
