<?php

declare(strict_types=1);

namespace App\Framework\WebPush\ValueObjects;

use App\Framework\Http\Url\Url;
use App\Framework\Http\Url\UrlFactory;

/**
 * Web Push Subscription.
 *
 * Repräsentiert eine Browser Push Subscription nach W3C Push API Standard.
 */
final readonly class PushSubscription
{
    public function __construct(
        public Url $endpoint,
        public string $p256dhKey,      // Client public key (Base64 URL-safe)
        public string $authToken,      // Client auth secret (Base64 URL-safe)
        public ?string $userId = null, // Optional: Associated user
        public ?string $userAgent = null,
        public ?\DateTimeImmutable $createdAt = null,
        public ?\DateTimeImmutable $expiresAt = null
    ) {
    }

    /**
     * Erstellt Subscription aus Browser PushSubscription JSON.
     *
     * @param array<string, mixed> $data Browser subscription data
     */
    public static function fromBrowserData(array $data, ?string $userId = null): self
    {
        $keys = $data['keys'] ?? [];

        return new self(
            endpoint: UrlFactory::parse($data['endpoint'] ?? ''),
            p256dhKey: $keys['p256dh'] ?? '',
            authToken: $keys['auth'] ?? '',
            userId: $userId,
            createdAt: new \DateTimeImmutable()
        );
    }

    /**
     * Erstellt Subscription aus Datenbank-Daten.
     *
     * @param array<string, mixed> $row Database row
     */
    public static function fromDatabaseRow(array $row): self
    {
        return new self(
            endpoint: UrlFactory::parse($row['endpoint']),
            p256dhKey: $row['p256dh_key'],
            authToken: $row['auth_token'],
            userId: $row['user_id'] ?? null,
            userAgent: $row['user_agent'] ?? null,
            createdAt: isset($row['created_at']) ? new \DateTimeImmutable($row['created_at']) : null,
            expiresAt: isset($row['expires_at']) ? new \DateTimeImmutable($row['expires_at']) : null
        );
    }

    /**
     * Prüft ob Subscription abgelaufen ist.
     */
    public function isExpired(): bool
    {
        if ($this->expiresAt === null) {
            return false;
        }

        return $this->expiresAt < new \DateTimeImmutable();
    }

    /**
     * Prüft ob Subscription noch gültig ist.
     */
    public function isValid(): bool
    {
        return ! $this->isExpired()
            && ! empty($this->endpoint->toString())
            && ! empty($this->p256dhKey)
            && ! empty($this->authToken);
    }

    /**
     * Konvertiert zu Array für Datenbank-Speicherung.
     *
     * @return array<string, mixed>
     */
    public function toArray(): array
    {
        return [
            'endpoint' => $this->endpoint->toString(),
            'p256dh_key' => $this->p256dhKey,
            'auth_token' => $this->authToken,
            'user_id' => $this->userId,
            'user_agent' => $this->userAgent,
            'created_at' => $this->createdAt?->format('Y-m-d H:i:s'),
            'expires_at' => $this->expiresAt?->format('Y-m-d H:i:s'),
        ];
    }

    /**
     * Generiert eindeutigen Hash für Subscription.
     */
    public function getHash(): string
    {
        return hash('sha256', $this->endpoint->toString());
    }
}
