<?php

namespace App\Http\Controllers\Api\Tenant;

use App\Enums\GuestNotificationAudience;
use App\Enums\GuestNotificationType;
use App\Http\Controllers\Controller;
use App\Http\Requests\Tenant\BroadcastGuestNotificationRequest;
use App\Http\Resources\Tenant\GuestNotificationResource;
use App\Models\Event;
use App\Models\GuestNotification;
use App\Models\GuestPolicySetting;
use App\Services\GuestNotificationService;
use App\Support\TenantMemberPermissions;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpFoundation\Response;

class EventGuestNotificationController extends Controller
{
    public function __construct(private readonly GuestNotificationService $notifications) {}

    public function index(Request $request, Event $event): JsonResponse
    {
        $this->assertEventTenant($request, $event);
        TenantMemberPermissions::ensureEventPermission($request, $event, 'guest-notifications:manage');

        $limit = max(1, min(100, (int) $request->integer('limit', 25)));

        $notifications = GuestNotification::query()
            ->forEvent($event)
            ->orderByDesc('id')
            ->limit($limit)
            ->get();

        return GuestNotificationResource::collection($notifications)->response();
    }

    public function store(BroadcastGuestNotificationRequest $request, Event $event): JsonResponse
    {
        $this->assertEventTenant($request, $event);
        TenantMemberPermissions::ensureEventPermission($request, $event, 'guest-notifications:manage');

        $data = $request->validated();

        $type = $this->resolveType($data['type'] ?? null);
        $audience = $this->resolveAudience($data['audience'] ?? null);
        $targetIdentifier = $audience === GuestNotificationAudience::GUEST
            ? $this->sanitizeIdentifier($data['guest_identifier'] ?? '')
            : null;

        if ($audience === GuestNotificationAudience::GUEST && ! $targetIdentifier) {
            throw ValidationException::withMessages([
                'guest_identifier' => __('Ein Gastname oder Geräte-Token wird benötigt.'),
            ]);
        }

        $expiresAt = null;
        if (! empty($data['expires_in_minutes'])) {
            $expiresAt = now()->addMinutes((int) $data['expires_in_minutes']);
        } else {
            $policyTtl = GuestPolicySetting::current()->guest_notification_ttl_hours;
            if ($policyTtl !== null && $policyTtl > 0) {
                $expiresAt = now()->addHours((int) $policyTtl);
            }
        }

        $payload = null;
        if (! empty($data['cta'])) {
            $payload = [
                'cta' => [
                    'label' => $data['cta']['label'],
                    'href' => $data['cta']['url'],
                ],
            ];
        }

        $notification = $this->notifications->createNotification(
            $event,
            $type,
            $data['title'],
            $data['message'],
            [
                'payload' => $payload,
                'audience_scope' => $audience,
                'target_identifier' => $targetIdentifier,
                'expires_at' => $expiresAt,
                'priority' => $data['priority'] ?? 1,
            ]
        );

        return (new GuestNotificationResource($notification))
            ->response()
            ->setStatusCode(Response::HTTP_CREATED);
    }

    private function assertEventTenant(Request $request, Event $event): void
    {
        $tenantId = $request->attributes->get('tenant_id');

        if ($tenantId === null || (int) $event->tenant_id !== (int) $tenantId) {
            abort(403, 'Event belongs to a different tenant.');
        }
    }

    private function resolveType(?string $value): GuestNotificationType
    {
        if (! $value) {
            return GuestNotificationType::BROADCAST;
        }

        foreach (GuestNotificationType::cases() as $type) {
            if ($type->value === $value) {
                return $type;
            }
        }

        return GuestNotificationType::BROADCAST;
    }

    private function resolveAudience(?string $value): GuestNotificationAudience
    {
        if (! $value) {
            return GuestNotificationAudience::ALL;
        }

        return $value === GuestNotificationAudience::GUEST->value
            ? GuestNotificationAudience::GUEST
            : GuestNotificationAudience::ALL;
    }

    private function sanitizeIdentifier(string $value): ?string
    {
        $normalized = preg_replace('/[^A-Za-z0-9 _\-]/', '', $value) ?? '';
        $normalized = trim(mb_substr($normalized, 0, 120));

        return $normalized === '' ? null : $normalized;
    }
}
