<?php

namespace App\Http\Controllers\Api\Tenant;

use App\Enums\GuestNotificationType;
use App\Http\Controllers\Controller;
use App\Http\Requests\Tenant\EventStoreRequest;
use App\Http\Resources\Tenant\EventJoinTokenResource;
use App\Http\Resources\Tenant\EventResource;
use App\Http\Resources\Tenant\PhotoResource;
use App\Models\CheckoutSession;
use App\Models\Event;
use App\Models\EventPackage;
use App\Models\GuestNotification;
use App\Models\Package;
use App\Models\PackagePurchase;
use App\Models\Photo;
use App\Models\Tenant;
use App\Models\User;
use App\Services\EventJoinTokenService;
use App\Support\ApiError;
use App\Support\TenantMemberPermissions;
use App\Support\WatermarkConfigResolver;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\HttpException;

class EventController extends Controller
{
    public function __construct(private readonly EventJoinTokenService $joinTokenService) {}

    public function index(Request $request): AnonymousResourceCollection
    {
        $tenantId = $request->attributes->get('tenant_id');

        if (! $tenantId) {
            throw ValidationException::withMessages([
                'tenant_id' => 'Tenant ID not found in request context.',
            ]);
        }

        $query = Event::where('tenant_id', $tenantId)
            ->with([
                'eventType',
                'eventPackages.package',
                'eventPackage.package',
            ])
            ->withCount([
                'photos',
                'photos as pending_photos_count' => fn ($photoQuery) => $photoQuery->where('status', 'pending'),
                'tasks as tasks_count',
                'joinTokens as total_join_tokens_count',
                'joinTokens as active_join_tokens_count' => fn ($tokenQuery) => $tokenQuery
                    ->whereNull('revoked_at')
                    ->where(function ($query) {
                        $query->whereNull('expires_at')
                            ->orWhere('expires_at', '>', now());
                    })
                    ->where(function ($query) {
                        $query->whereNull('usage_limit')
                            ->orWhereColumn('usage_limit', '>', 'usage_count');
                    }),
            ])
            ->withSum('photos as likes_sum', 'likes_count')
            ->orderBy('created_at', 'desc');

        if ($request->has('status')) {
            $query->where('status', $request->status);
        }

        if ($request->has('type_id')) {
            $query->where('event_type_id', $request->type_id);
        }

        $events = $query->paginate($request->get('per_page', 15));

        return EventResource::collection($events);
    }

    public function store(EventStoreRequest $request): JsonResponse
    {
        TenantMemberPermissions::ensureTenantPermission($request, 'events:manage');

        $tenant = $request->attributes->get('tenant');
        if (! $tenant instanceof Tenant) {
            $tenantId = $request->attributes->get('tenant_id');
            $tenant = Tenant::findOrFail($tenantId);
        }

        $actor = $request->user();
        $isSuperAdmin = $actor instanceof User && $actor->isSuperAdmin();

        // Package check is now handled by middleware

        $validated = $request->validated();
        $tenantId = $tenant->id;

        $requestedPackageId = $isSuperAdmin ? $request->integer('package_id') : null;
        unset($validated['package_id']);
        $requestedServiceSlug = $request->input('service_package_slug');
        $requestedServiceSlug = is_string($requestedServiceSlug) && $requestedServiceSlug !== '' ? $requestedServiceSlug : null;
        unset($validated['service_package_slug']);

        $tenantPackage = $tenant->tenantPackages()
            ->with('package')
            ->where('active', true)
            ->orderByDesc('purchased_at')
            ->first();

        $package = null;

        if ($requestedPackageId) {
            $package = Package::query()->find($requestedPackageId);
        }

        if (! $package && $isSuperAdmin) {
            $package = $this->resolveOwnerPackage();
        }

        $billingTenantPackage = null;
        if (! $package) {
            $billingTenantPackage = $requestedServiceSlug
                ? $tenant->getActiveResellerPackageFor($requestedServiceSlug)
                : $tenant->getActiveResellerPackage();

            if ($billingTenantPackage && $billingTenantPackage->package) {
                $package = $billingTenantPackage->package;
                $requestedServiceSlug = $requestedServiceSlug ?: $package->included_package_slug;
            }
        }

        if (! $package && $tenantPackage) {
            $package = $tenantPackage->package ?? Package::query()->find($tenantPackage->package_id);
        }

        if (! $package) {
            throw ValidationException::withMessages([
                'package_id' => __('Aktuell ist kein aktives Paket verfügbar. Bitte buche zunächst ein Paket.'),
            ]);
        }

        $billingIsReseller = $package->isReseller();
        $eventServicePackage = $billingIsReseller
            ? $this->resolveResellerEventPackageForSlug($requestedServiceSlug ?: $package->included_package_slug)
            : $package;

        $requiresWaiver = $package->isEndcustomer();
        $latestPurchase = $requiresWaiver ? $this->resolveLatestPackagePurchase($tenant, $package) : null;
        $existingWaiver = $latestPurchase ? data_get($latestPurchase->metadata, 'consents.digital_content_waiver_at') : null;
        $needsWaiver = ! $isSuperAdmin && $requiresWaiver && ! $existingWaiver;

        if ($needsWaiver && ! $request->boolean('accepted_waiver')) {
            throw ValidationException::withMessages([
                'accepted_waiver' => 'Ein sofortiger Beginn der digitalen Dienstleistung erfordert Ihre ausdrückliche Zustimmung.',
            ]);
        }

        $eventData = array_merge($validated, [
            'tenant_id' => $tenantId,
            'status' => $validated['status'] ?? 'draft',
            'slug' => $this->generateUniqueSlug($validated['name'], $tenantId),
        ]);

        if (isset($eventData['event_date'])) {
            $eventData['date'] = $eventData['event_date'];
            unset($eventData['event_date']);
        }

        $settings = $eventData['settings'] ?? [];
        foreach (['public_url', 'custom_domain', 'theme_color'] as $key) {
            if (array_key_exists($key, $eventData)) {
                $settings[$key] = $eventData[$key];
                unset($eventData[$key]);
            }
        }

        if (isset($eventData['features'])) {
            $settings['features'] = $eventData['features'];
            unset($eventData['features']);
        }

        $settings['branding_allowed'] = $eventServicePackage->branding_allowed !== false;
        $settings['watermark_allowed'] = $eventServicePackage->watermark_allowed !== false;

        $eventData['settings'] = $settings;

        foreach (['password', 'password_confirmation', 'password_protected', 'logo_image', 'cover_image'] as $unused) {
            unset($eventData[$unused]);
        }

        $allowed = [
            'tenant_id',
            'name',
            'description',
            'date',
            'slug',
            'location',
            'max_participants',
            'settings',
            'event_type_id',
            'is_active',
            'join_link_enabled',
            'photo_upload_enabled',
            'task_checklist_enabled',
            'default_locale',
            'status',
        ];

        $eventData = Arr::only($eventData, $allowed);

        $event = DB::transaction(function () use ($tenant, $eventData, $eventServicePackage, $billingIsReseller, $isSuperAdmin) {
            $event = Event::create($eventData);

            EventPackage::create([
                'event_id' => $event->id,
                'package_id' => $eventServicePackage->id,
                'purchased_price' => $billingIsReseller ? 0 : $eventServicePackage->price,
                'purchased_at' => now(),
                'gallery_expires_at' => $eventServicePackage->gallery_days
                    ? now()->addDays($eventServicePackage->gallery_days)
                    : null,
            ]);

            if ($billingIsReseller && ! $isSuperAdmin) {
                $note = sprintf('Event #%d created (%s)', $event->id, $event->name);

                if (! $tenant->consumeEventAllowanceFor($eventServicePackage->slug, 1, 'event.create', $note)) {
                    throw new HttpException(402, 'Insufficient package allowance.');
                }
            }

            return $event;
        });

        if ($needsWaiver) {
            $this->recordEventStartWaiver($tenant, $package, $latestPurchase);
        }

        $tenant->refresh();
        $event->load(['eventType', 'tenant', 'eventPackages.package', 'eventPackages.addons']);

        return response()->json([
            'message' => 'Event created successfully',
            'data' => new EventResource($event),
            'package' => $event->eventPackage ? $event->eventPackage->package->name : 'None',
            'remaining_events' => $tenant->activeResellerPackage ? $tenant->activeResellerPackage->remaining_events : 0,
        ], 201);
    }

    private function resolveResellerDefaultEventPackage(): Package
    {
        return $this->resolveResellerEventPackageForSlug('standard');
    }

    private function resolveResellerEventPackageForSlug(?string $slug): Package
    {
        if (is_string($slug) && $slug !== '') {
            $match = Package::query()
                ->where('type', 'endcustomer')
                ->where('slug', $slug)
                ->first();

            if ($match) {
                return $match;
            }
        }

        $default = Package::query()
            ->where('type', 'endcustomer')
            ->where('slug', 'standard')
            ->first();

        if ($default) {
            return $default;
        }

        $fallback = Package::query()
            ->where('type', 'endcustomer')
            ->orderBy('price')
            ->first();

        if (! $fallback) {
            throw ValidationException::withMessages([
                'package_id' => __('Aktuell ist kein Endkunden-Paket verfügbar. Bitte kontaktiere den Support.'),
            ]);
        }

        return $fallback;
    }

    private function resolveLatestPackagePurchase(Tenant $tenant, Package $package): ?PackagePurchase
    {
        return PackagePurchase::query()
            ->where('tenant_id', $tenant->id)
            ->where('package_id', $package->id)
            ->orderByDesc('purchased_at')
            ->orderByDesc('id')
            ->first();
    }

    private function resolveOwnerPackage(): ?Package
    {
        $ownerPackage = Package::query()
            ->where('slug', 'pro')
            ->first();

        return $ownerPackage ?? Package::query()->find(3);
    }

    private function recordEventStartWaiver(Tenant $tenant, Package $package, ?PackagePurchase $purchase): void
    {
        $timestamp = now();
        $legalVersion = config('app.legal_version', $timestamp->toDateString());

        if ($purchase) {
            $metadata = $purchase->metadata ?? [];
            $consents = is_array($metadata['consents'] ?? null) ? $metadata['consents'] : [];
            $consents['digital_content_waiver_at'] = $timestamp->toIso8601String();
            $consents['legal_version'] = $consents['legal_version'] ?? $legalVersion;
            $metadata['consents'] = $consents;
            $purchase->metadata = $metadata;
            $purchase->save();
        }

        $session = CheckoutSession::query()
            ->where('tenant_id', $tenant->id)
            ->where('package_id', $package->id)
            ->where('status', CheckoutSession::STATUS_COMPLETED)
            ->orderByDesc('completed_at')
            ->first();

        if ($session && ! $session->digital_content_waiver_at) {
            $session->digital_content_waiver_at = $timestamp;
            $session->legal_version = $session->legal_version ?? $legalVersion;
            $session->save();
        }
    }

    public function show(Request $request, Event $event): JsonResponse
    {
        $tenantId = $request->attributes->get('tenant_id');

        if ($event->tenant_id !== $tenantId) {
            return ApiError::response(
                'event_not_found',
                'Event not accessible',
                'Das Event konnte nicht gefunden werden.',
                404,
                ['event_slug' => $event->slug ?? null]
            );
        }

        $event->load([
            'eventType',
            'photos' => fn ($query) => $query->with('likes')->latest(),
            'tasks',
            'tenant' => fn ($query) => $query->select('id', 'name'),
            'eventPackages' => fn ($query) => $query
                ->with(['package', 'addons'])
                ->orderByDesc('purchased_at')
                ->orderByDesc('created_at'),
        ]);

        return response()->json([
            'data' => new EventResource($event),
        ]);
    }

    public function update(EventStoreRequest $request, Event $event): JsonResponse
    {
        $tenantId = $request->attributes->get('tenant_id');
        $event->loadMissing('eventPackage.package');

        if ($event->tenant_id !== $tenantId) {
            return ApiError::response(
                'event_not_found',
                'Event not accessible',
                'Das Event konnte nicht gefunden werden.',
                404,
                ['event_slug' => $event->slug ?? null]
            );
        }

        TenantMemberPermissions::ensureEventPermission($request, $event, 'events:manage');

        $validated = $request->validated();
        $nameProvided = array_key_exists('name', $validated);

        $validated = array_merge([
            'name' => $event->name,
            'event_type_id' => $event->event_type_id,
            'event_date' => $event->date?->toDateString(),
            'status' => $event->status,
        ], $validated);

        if (isset($validated['event_date'])) {
            $validated['date'] = $validated['event_date'];
            unset($validated['event_date']);
        }

        if ($nameProvided && $validated['name'] !== $event->name) {
            $validated['slug'] = $this->generateUniqueSlug($validated['name'], $tenantId, $event->id);
        }

        foreach (['password', 'password_confirmation', 'password_protected'] as $unused) {
            unset($validated[$unused]);
        }

        $package = $event->eventPackage?->package;
        $brandingAllowed = optional($package)->branding_allowed !== false;
        $watermarkAllowed = optional($package)->watermark_allowed !== false;
        $watermarkRemovalAllowed = WatermarkConfigResolver::determineRemovalAllowed($event);

        if (isset($validated['settings']) && is_array($validated['settings'])) {
            $validated['settings'] = array_merge($event->settings ?? [], $validated['settings']);
        } else {
            $validated['settings'] = $event->settings ?? [];
        }

        $validated['settings']['branding_allowed'] = $brandingAllowed;
        $validated['settings']['watermark_allowed'] = $watermarkAllowed;
        $validated['settings']['watermark_removal_allowed'] = $watermarkRemovalAllowed;

        $settings = $validated['settings'];
        $branding = Arr::get($settings, 'branding', []);
        $watermark = Arr::get($settings, 'watermark', []);
        $existingWatermark = is_array($watermark) ? $watermark : [];

        if (is_array($branding)) {
            $settings['branding'] = $this->normalizeBrandingSettings($branding, $event, $brandingAllowed);
        }

        if (is_array($watermark)) {
            $mode = $watermark['mode'] ?? 'base';

            if (! $watermarkAllowed) {
                $mode = 'base';
            } elseif (! $brandingAllowed) {
                $mode = 'base';
            } elseif ($mode === 'off' && ! $watermarkRemovalAllowed) {
                $mode = 'base';
            }

            $assetPath = $watermark['asset'] ?? null;
            $assetDataUrl = $watermark['asset_data_url'] ?? null;

            if (! $watermarkAllowed || $mode === 'off') {
                $assetPath = null;
            }

            if ($assetDataUrl && $mode === 'custom' && $brandingAllowed) {
                if (! preg_match('/^data:image\\/(png|webp|jpe?g|svg\\+xml);base64,(.+)$/i', $assetDataUrl, $matches)) {
                    throw ValidationException::withMessages([
                        'settings.watermark.asset_data_url' => __('Ungültiges Wasserzeichen-Bild.'),
                    ]);
                }

                $decoded = base64_decode($matches[2], true);

                if ($decoded === false) {
                    throw ValidationException::withMessages([
                        'settings.watermark.asset_data_url' => __('Wasserzeichen konnte nicht gelesen werden.'),
                    ]);
                }

                if (strlen($decoded) > 3 * 1024 * 1024) { // 3 MB
                    throw ValidationException::withMessages([
                        'settings.watermark.asset_data_url' => __('Wasserzeichen ist zu groß (max. 3 MB).'),
                    ]);
                }

                $mime = strtolower($matches[1]);
                $extension = match (true) {
                    str_starts_with($mime, 'jp') => 'jpg',
                    str_starts_with($mime, 'svg') => 'svg',
                    default => $mime,
                };
                $path = sprintf('branding/watermarks/event-%s.%s', $event->id, $extension);
                Storage::disk('public')->put($path, $decoded);
                $assetPath = $path;
            }

            $position = $watermark['position'] ?? 'bottom-right';
            $validPositions = [
                'top-left',
                'top-center',
                'top-right',
                'middle-left',
                'center',
                'middle-right',
                'bottom-left',
                'bottom-center',
                'bottom-right',
            ];

            if (! in_array($position, $validPositions, true)) {
                $position = 'bottom-right';
            }

            $settings['watermark'] = [
                'mode' => $mode,
                'asset' => $assetPath,
                'position' => $position,
                'opacity' => isset($watermark['opacity']) ? (float) $watermark['opacity'] : ($existingWatermark['opacity'] ?? null),
                'scale' => isset($watermark['scale']) ? (float) $watermark['scale'] : ($existingWatermark['scale'] ?? null),
                'padding' => isset($watermark['padding']) ? (int) $watermark['padding'] : ($existingWatermark['padding'] ?? null),
                'offset_x' => isset($watermark['offset_x']) ? (int) $watermark['offset_x'] : ($existingWatermark['offset_x'] ?? 0),
                'offset_y' => isset($watermark['offset_y']) ? (int) $watermark['offset_y'] : ($existingWatermark['offset_y'] ?? 0),
            ];
        }

        if (array_key_exists('watermark_serve_originals', $settings)) {
            $settings['watermark_serve_originals'] = (bool) $settings['watermark_serve_originals'];
        }

        $validated['settings'] = $settings;

        $event->update($validated);
        $event->load(['eventType', 'tenant']);

        return response()->json([
            'message' => 'Event updated successfully',
            'data' => new EventResource($event),
        ]);
    }

    /**
     * @param  array<string, mixed>  $branding
     * @return array<string, mixed>
     */
    private function normalizeBrandingSettings(array $branding, Event $event, bool $brandingAllowed): array
    {
        $logoDataUrl = $branding['logo_data_url'] ?? null;

        if (! $brandingAllowed) {
            unset($branding['logo_data_url']);

            return $branding;
        }

        if (! is_string($logoDataUrl) || trim($logoDataUrl) === '') {
            unset($branding['logo_data_url']);

            return $branding;
        }

        if (! preg_match('/^data:image\\/(png|webp|jpe?g);base64,(.+)$/i', $logoDataUrl, $matches)) {
            throw ValidationException::withMessages([
                'settings.branding.logo_data_url' => __('Ungültiges Branding-Logo.'),
            ]);
        }

        $decoded = base64_decode($matches[2], true);

        if ($decoded === false) {
            throw ValidationException::withMessages([
                'settings.branding.logo_data_url' => __('Branding-Logo konnte nicht gelesen werden.'),
            ]);
        }

        if (strlen($decoded) > 1024 * 1024) { // 1 MB
            throw ValidationException::withMessages([
                'settings.branding.logo_data_url' => __('Branding-Logo ist zu groß (max. 1 MB).'),
            ]);
        }

        $extension = str_starts_with(strtolower($matches[1]), 'jp') ? 'jpg' : strtolower($matches[1]);
        $path = sprintf('branding/logos/event-%s.%s', $event->id, $extension);
        Storage::disk('public')->put($path, $decoded);

        $branding['logo_url'] = $path;
        $branding['logo_mode'] = 'upload';
        $branding['logo_value'] = $path;

        $logo = $branding['logo'] ?? [];
        if (! is_array($logo)) {
            $logo = [];
        }

        $logo['mode'] = 'upload';
        $logo['value'] = $path;
        $branding['logo'] = $logo;

        unset($branding['logo_data_url']);

        return $branding;
    }

    public function destroy(Request $request, Event $event): JsonResponse
    {
        $tenantId = $request->attributes->get('tenant_id');

        if ($event->tenant_id !== $tenantId) {
            return ApiError::response(
                'event_not_found',
                'Event not accessible',
                'Das Event konnte nicht gefunden werden.',
                404,
                ['event_slug' => $event->slug ?? null]
            );
        }

        TenantMemberPermissions::ensureEventPermission($request, $event, 'events:manage');

        $event->delete();

        return response()->json([
            'message' => 'Event deleted successfully',
        ]);
    }

    public function stats(Request $request, Event $event): JsonResponse
    {
        $tenantId = $request->attributes->get('tenant_id');

        if ($event->tenant_id !== $tenantId) {
            return ApiError::response(
                'event_not_found',
                'Event not accessible',
                'Das Event konnte nicht gefunden werden.',
                404,
                ['event_slug' => $event->slug ?? null]
            );
        }

        $totalPhotos = Photo::where('event_id', $event->id)->count();
        $featuredPhotos = Photo::where('event_id', $event->id)->where('is_featured', true)->count();
        $likes = Photo::where('event_id', $event->id)->sum('likes_count');
        $recentUploads = Photo::where('event_id', $event->id)
            ->where('created_at', '>=', now()->subDays(7))
            ->count();

        return response()->json([
            'total' => $totalPhotos,
            'featured' => $featuredPhotos,
            'likes' => (int) $likes,
            'recent_uploads' => $recentUploads,
            'status' => $event->status,
            'is_active' => (bool) $event->is_active,
        ]);
    }

    public function toolkit(Request $request, Event $event): JsonResponse
    {
        $tenantId = $request->attributes->get('tenant_id');

        if ($event->tenant_id !== $tenantId) {
            return ApiError::response(
                'event_not_found',
                'Event not accessible',
                'Das Event konnte nicht gefunden werden.',
                404,
                ['event_slug' => $event->slug ?? null]
            );
        }

        $event->load(['eventType', 'eventPackage.package']);

        $photoQuery = Photo::query()->where('event_id', $event->id);
        $pendingPhotos = (clone $photoQuery)
            ->where('status', 'pending')
            ->latest('created_at')
            ->take(6)
            ->get();

        $recentUploads = (clone $photoQuery)
            ->where('status', 'approved')
            ->latest('created_at')
            ->take(8)
            ->get();

        $pendingCount = (clone $photoQuery)->where('status', 'pending')->count();
        $uploads24h = (clone $photoQuery)->where('created_at', '>=', now()->subDay())->count();
        $totalUploads = (clone $photoQuery)->count();

        $tasks = $event->tasks()
            ->orderBy('tasks.sort_order')
            ->orderBy('tasks.created_at')
            ->get(['tasks.id', 'tasks.title', 'tasks.description', 'tasks.priority', 'tasks.is_completed']);

        $taskSummary = [
            'total' => $tasks->count(),
            'completed' => $tasks->where('is_completed', true)->count(),
        ];
        $taskSummary['pending'] = max(0, $taskSummary['total'] - $taskSummary['completed']);

        $translate = static function ($value, ?string $fallback = '') {
            if (is_array($value)) {
                $locale = app()->getLocale();
                $candidates = array_filter([
                    $locale,
                    $locale && str_contains($locale, '-') ? explode('-', $locale)[0] : null,
                    'de',
                    'en',
                ]);

                foreach ($candidates as $candidate) {
                    if ($candidate && isset($value[$candidate]) && $value[$candidate] !== '') {
                        return $value[$candidate];
                    }
                }

                $first = reset($value);

                return $first !== false ? $first : $fallback;
            }

            if (is_string($value) && $value !== '') {
                return $value;
            }

            return $fallback;
        };

        $taskPreview = $tasks
            ->take(6)
            ->map(fn ($task) => [
                'id' => $task->id,
                'title' => $translate($task->title, 'Task'),
                'description' => $translate($task->description, null),
                'is_completed' => (bool) $task->is_completed,
                'priority' => $task->priority,
            ])
            ->values();

        $joinTokenQuery = $event->joinTokens();
        $totalInvites = (clone $joinTokenQuery)->count();
        $activeInvites = (clone $joinTokenQuery)
            ->whereNull('revoked_at')
            ->where(function ($query) {
                $query->whereNull('expires_at')
                    ->orWhere('expires_at', '>', now());
            })
            ->where(function ($query) {
                $query->whereNull('usage_limit')
                    ->orWhereColumn('usage_limit', '>', 'usage_count');
            })
            ->count();

        $recentInvites = (clone $joinTokenQuery)
            ->orderByDesc('created_at')
            ->take(3)
            ->get();

        $notificationQuery = GuestNotification::query()->where('event_id', $event->id);
        $notificationTotal = (clone $notificationQuery)->count();
        $notificationTypeCounts = (clone $notificationQuery)
            ->select('type', DB::raw('COUNT(*) as total'))
            ->groupBy('type')
            ->pluck('total', 'type')
            ->map(fn ($value) => (int) $value)
            ->toArray();
        $lastNotificationAt = $notificationTotal > 0
            ? (clone $notificationQuery)->latest('created_at')->value('created_at')
            : null;
        $lastBroadcast = (clone $notificationQuery)
            ->where('type', GuestNotificationType::BROADCAST->value)
            ->latest('created_at')
            ->first(['id', 'title', 'created_at']);
        $recentNotifications = (clone $notificationQuery)
            ->latest('created_at')
            ->limit(5)
            ->get(['id', 'title', 'type', 'status', 'audience_scope', 'created_at']);

        $notificationsPayload = [
            'summary' => [
                'total' => $notificationTotal,
                'last_sent_at' => $lastNotificationAt ? $lastNotificationAt->toAtomString() : null,
                'by_type' => $notificationTypeCounts,
                'broadcasts' => [
                    'total' => $notificationTypeCounts[GuestNotificationType::BROADCAST->value] ?? 0,
                    'last_title' => $lastBroadcast?->title,
                    'last_sent_at' => $lastBroadcast?->created_at?->toAtomString(),
                ],
            ],
            'recent' => $recentNotifications->map(fn (GuestNotification $notification) => [
                'id' => $notification->id,
                'title' => $notification->title,
                'type' => $notification->type->value,
                'status' => $notification->status->value,
                'audience_scope' => $notification->audience_scope->value,
                'created_at' => $notification->created_at?->toAtomString(),
            ])->all(),
        ];

        $alerts = [];
        if (($event->settings['engagement_mode'] ?? 'tasks') !== 'photo_only' && $taskSummary['total'] === 0) {
            $alerts[] = 'no_tasks';
        }
        if ($activeInvites === 0) {
            $alerts[] = 'no_invites';
        }
        if ($pendingCount > 0) {
            $alerts[] = 'pending_photos';
        }

        return response()->json([
            'event' => new EventResource($event),
            'metrics' => [
                'uploads_total' => $totalUploads,
                'uploads_24h' => $uploads24h,
                'pending_photos' => $pendingCount,
                'active_invites' => $activeInvites,
                'engagement_mode' => $event->settings['engagement_mode'] ?? 'tasks',
            ],
            'tasks' => [
                'summary' => $taskSummary,
                'items' => $taskPreview,
            ],
            'photos' => [
                'pending' => PhotoResource::collection($pendingPhotos)->resolve($request),
                'recent' => PhotoResource::collection($recentUploads)->resolve($request),
            ],
            'invites' => [
                'summary' => [
                    'total' => $totalInvites,
                    'active' => $activeInvites,
                ],
                'items' => EventJoinTokenResource::collection($recentInvites)->resolve($request),
            ],
            'notifications' => $notificationsPayload,
            'alerts' => $alerts,
        ]);
    }

    public function toggle(Request $request, Event $event): JsonResponse
    {
        $tenantId = $request->attributes->get('tenant_id');

        if ($event->tenant_id !== $tenantId) {
            return ApiError::response(
                'event_not_found',
                'Event not accessible',
                'Das Event konnte nicht gefunden werden.',
                404,
                ['event_slug' => $event->slug ?? null]
            );
        }

        $activate = ! (bool) $event->is_active;
        $event->is_active = $activate;

        if ($activate) {
            $event->status = 'published';
        } elseif ($event->status === 'published') {
            $event->status = 'draft';
        }

        $event->save();
        $event->refresh()->load(['eventType', 'tenant']);

        return response()->json([
            'message' => $activate ? 'Event activated' : 'Event deactivated',
            'data' => new EventResource($event),
            'is_active' => (bool) $event->is_active,
        ]);
    }

    public function createInvite(Request $request, Event $event): JsonResponse
    {
        $tenantId = $request->attributes->get('tenant_id');

        if ($event->tenant_id !== $tenantId) {
            return ApiError::response(
                'event_not_found',
                'Event not accessible',
                'Das Event konnte nicht gefunden werden.',
                404,
                ['event_slug' => $event->slug ?? null]
            );
        }

        $validated = $request->validate([
            'label' => ['nullable', 'string', 'max:255'],
            'expires_at' => ['nullable', 'date', 'after:now'],
            'usage_limit' => ['nullable', 'integer', 'min:1'],
        ]);

        $attributes = array_filter([
            'label' => $validated['label'] ?? null,
            'expires_at' => $validated['expires_at'] ?? null,
            'usage_limit' => $validated['usage_limit'] ?? null,
            'created_by' => $request->user()?->id,
        ], fn ($value) => ! is_null($value));

        $joinToken = $this->joinTokenService->createToken($event, $attributes);

        return response()->json([
            'link' => url("/e/{$event->slug}?invite={$joinToken->token}"),
            'token' => $joinToken->token,
            'token_url' => url('/e/'.$joinToken->token),
            'join_token' => new EventJoinTokenResource($joinToken),
        ]);
    }

    public function bulkUpdateStatus(Request $request): JsonResponse
    {
        $tenantId = $request->attributes->get('tenant_id');
        $validated = $request->validate([
            'event_ids' => 'required|array',
            'event_ids.*' => 'exists:events,id',
            'status' => 'required|in:draft,published,archived',
        ]);

        $updatedCount = Event::whereIn('id', $validated['event_ids'])
            ->where('tenant_id', $tenantId)
            ->update(['status' => $validated['status']]);

        return response()->json([
            'message' => "{$updatedCount} events updated successfully",
            'updated_count' => $updatedCount,
        ]);
    }

    private function generateUniqueSlug(string $name, int $tenantId, ?int $excludeId = null): string
    {
        $slug = Str::slug($name);
        $originalSlug = $slug;
        $counter = 1;

        while (Event::where('slug', $slug)
            ->where('tenant_id', $tenantId)
            ->when($excludeId, fn ($query) => $query->where('id', '!=', $excludeId))
            ->exists()) {
            $slug = $originalSlug.'-'.$counter;
            $counter++;
        }

        return $slug;
    }

    public function search(Request $request): AnonymousResourceCollection
    {
        $tenantId = $request->attributes->get('tenant_id');
        $query = $request->get('q', '');

        if (strlen($query) < 2) {
            return EventResource::collection(collect([]));
        }

        $events = Event::where('tenant_id', $tenantId)
            ->where(function ($q) use ($query) {
                $q->where('name', 'like', "%{$query}%")
                    ->orWhere('description', 'like', "%{$query}%");
            })
            ->with('eventType')
            ->limit(10)
            ->get();

        return EventResource::collection($events);
    }
}
