<?php
namespace App\Http\Controllers;
use App\Jobs\GenerateAiCardJob;
use App\Models\Vcard;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Rule;
class OnboardingController extends Controller
{
/** Show the onboarding form */
public function create()
{
return view('vcard.onboarding');
}
/**
* Store: accept 15 source URLs, create VCard skeleton, dispatch AI job.
* Input: sources[] array (or legacy social_url string)
*/
public function store(Request $request): \Illuminate\Http\RedirectResponse
{
// Support both legacy single URL and new multi-source array
if ($request->has('social_url') && !$request->has('sources')) {
$request->merge(['sources' => [$request->input('social_url')]]);
}
$request->validate([
'sources' => ['required', 'array', 'min:1', 'max:5'],
'sources.*' => ['required', 'url', 'max:500', 'distinct'],
], [
'sources.required' => 'Fornea pelo menos uma URL de rede social ou site.',
'sources.max' => 'Pode fornecer no mximo 5 fontes.',
'sources.*.url' => 'Uma das URLs fornecidas no vlida.',
'sources.*.distinct' => 'No repita URLs.',
]);
$user = Auth::user();
$sources = array_filter($request->sources, fn($s) => !empty(trim($s)));
// Determine primary URL for backward compatibility
$primaryUrl = $sources[0] ?? '';
// Create VCard skeleton
$vcard = Vcard::create([
'user_id' => $user->id,
'tenant_id' => $user->tenant_id ?? null,
'name' => $user->name,
'url_alias' => 'card-' . uniqid(),
'status' => 'pending_payment',
'ai_status' => 'pending',
'ai_social_url' => json_encode(array_values($sources), JSON_UNESCAPED_SLASHES),
'payment_deadline' => now()->addHours(24),
'template_id' => 1,
]);
Log::info("[Onboarding] VCard#{$vcard->id} created. Sources: " . implode(', ', $sources));
// Dispatch AI job with full sources array
GenerateAiCardJob::dispatch($user, $sources, $vcard->id)
->onQueue('ai-generation');
return redirect()->route('vcard.processing', ['vcard' => $vcard->id])
->with('message', count($sources) > 1
? 'A IA est a analisar ' . count($sources) . ' fontes para criar o seu carto...'
: 'A IA est a preparar o seu carto...'
);
}
/** Show processing screen */
public function processing(Vcard $vcard)
{
if ($vcard->user_id !== Auth::id()) {
abort(403);
}
return view('vcard.processing', compact('vcard'));
}
/** API: Poll AI status */
public function aiStatus(Vcard $vcard): JsonResponse
{
if ($vcard->user_id !== Auth::id()) {
return response()->json(['error' => 'Unauthorized'], 403);
}
$aiData = null;
if ($vcard->ai_status === 'completed' && $vcard->ai_data) {
$decoded = json_decode($vcard->ai_data, true);
$aiData = [
'template_id' => $decoded['template_id'] ?? null,
'color_primary' => $decoded['color_primary'] ?? null,
'confidence' => $decoded['confidence'] ?? null,
'brand_personality' => $decoded['brand_personality'] ?? null,
];
}
return response()->json([
'vcard_id' => $vcard->id,
'ai_status' => $vcard->ai_status,
'template_id' => $vcard->template_id,
'ai_data' => $aiData,
'redirect_url' => $vcard->ai_status === 'completed'
? route('user.vcard.edit', $vcard->id)
: null,
]);
}
}
|