<?php

declare(strict_types=1);

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

use App\Http\Requests\Account\UpdateProfileRequest;
use App\Http\Resources\UserResource;
use App\Services\Audit\AuditEvent;
use App\Services\Audit\AuditRecorder;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;

final class ProfileController extends Controller
{
    public function __construct(
        private readonly AuditRecorder $audit,
    ) {}

    /** The signed-in user's own account, used to hydrate the SPA on boot. */
    public function show(Request $request): JsonResponse
    {
        // Eager-loaded explicitly: the resource reads verifications, and the
        // lazy-load guard now enforces that rather than silently querying.
        $user = $request->user()->load(['profile', 'sellerProfile', 'verifications']);

        return response()->json(['data' => UserResource::make($user)]);
    }

    public function update(UpdateProfileRequest $request): JsonResponse
    {
        $user = $request->user();
        $profile = $user->profile()->firstOrCreate([]);

        Gate::authorize('update', $profile);

        DB::transaction(function () use ($request, $user, $profile): void {
            $userAttributes = $request->userAttributes();
            $profileAttributes = $request->profileAttributes();

            /*
             * Preferences arrive as a partial map, so they are merged over what
             * is stored. Replacing wholesale would silently reset every switch
             * the client did not happen to send.
             */
            if (array_key_exists('notification_preferences', $profileAttributes)) {
                $profileAttributes['notification_preferences'] = array_merge(
                    $profile->preferences(),
                    $profileAttributes['notification_preferences'],
                );
            }

            if ($userAttributes !== []) {
                $user->fill($userAttributes);

                /*
                 * Changing the phone number invalidates the badge earned by the
                 * old one -- a verified marker must always refer to the value
                 * that was actually verified.
                 */
                if ($user->isDirty('phone')) {
                    $user->phone_verified_at = null;
                }

                $this->audit->recordChanges(AuditEvent::USER_PROFILE_UPDATED, $user);
                $user->save();
            }

            if ($profileAttributes !== []) {
                $profile->fill($profileAttributes);
                $this->audit->recordChanges(AuditEvent::USER_PROFILE_UPDATED, $profile);
                $profile->save();
            }
        });

        return response()->json([
            'message' => 'Profile updated.',
            'data' => UserResource::make($user->fresh(['profile', 'sellerProfile', 'verifications'])),
        ]);
    }
}
