<?php

declare(strict_types=1);

namespace App\Framework\WebPush\ValueObjects;

use App\Framework\Core\ValueObjects\Url;

/**
 * Push Notification Message.
 *
 * Repräsentiert eine Web Push Notification nach W3C Notification API Standard.
 */
final readonly class PushMessage
{
    /**
     * @param NotificationAction[] $actions
     * @param array<string, mixed> $data
     */
    public function __construct(
        public string $title,
        public string $body,
        public ?Url $icon = null,
        public ?Url $badge = null,
        public ?Url $image = null,
        public ?string $tag = null,
        public bool $requireInteraction = false,
        public bool $silent = false,
        public array $actions = [],
        public array $data = [],
        public ?int $ttl = 86400 // Time to live in seconds (default: 24h)
    ) {
    }

    /**
     * Erstellt einfache Text-Notification.
     */
    public static function simple(string $title, string $body): self
    {
        return new self(title: $title, body: $body);
    }

    /**
     * Erstellt Notification mit Icon.
     */
    public static function withIcon(string $title, string $body, string $iconUrl): self
    {
        return new self(
            title: $title,
            body: $body,
            icon: new Url($iconUrl)
        );
    }

    /**
     * Konvertiert zu Browser Notification Payload.
     *
     * @return array<string, mixed>
     */
    public function toNotificationPayload(): array
    {
        $payload = [
            'title' => $this->title,
            'body' => $this->body,
            'requireInteraction' => $this->requireInteraction,
            'silent' => $this->silent,
        ];

        if ($this->icon !== null) {
            $payload['icon'] = $this->icon->toString();
        }

        if ($this->badge !== null) {
            $payload['badge'] = $this->badge->toString();
        }

        if ($this->image !== null) {
            $payload['image'] = $this->image->toString();
        }

        if ($this->tag !== null) {
            $payload['tag'] = $this->tag;
        }

        if (! empty($this->actions)) {
            $payload['actions'] = array_map(
                fn (NotificationAction $action) => $action->toArray(),
                $this->actions
            );
        }

        if (! empty($this->data)) {
            $payload['data'] = $this->data;
        }

        return $payload;
    }

    /**
     * Konvertiert zu JSON für Push Service.
     */
    public function toJson(): string
    {
        return json_encode($this->toNotificationPayload());
    }

    /**
     * Mit zusätzlichen Daten.
     *
     * @param array<string, mixed> $data
     */
    public function withData(array $data): self
    {
        return new self(
            title: $this->title,
            body: $this->body,
            icon: $this->icon,
            badge: $this->badge,
            image: $this->image,
            tag: $this->tag,
            requireInteraction: $this->requireInteraction,
            silent: $this->silent,
            actions: $this->actions,
            data: array_merge($this->data, $data),
            ttl: $this->ttl
        );
    }

    /**
     * Mit Actions.
     *
     * @param NotificationAction[] $actions
     */
    public function withActions(array $actions): self
    {
        return new self(
            title: $this->title,
            body: $this->body,
            icon: $this->icon,
            badge: $this->badge,
            image: $this->image,
            tag: $this->tag,
            requireInteraction: $this->requireInteraction,
            silent: $this->silent,
            actions: $actions,
            data: $this->data,
            ttl: $this->ttl
        );
    }
}
