<?php

declare(strict_types=1);

/*
 * This file is part of the Ferienpass package.
 *
 * (c) Richard Henkenjohann <richard@ferienpass.online>
 *
 * For more information visit the project website <https://ferienpass.online>
 * or the documentation under <https://docs.ferienpass.online>.
 */

namespace Ferienpass\CoreBundle\Message;

use Ferienpass\CoreBundle\Entity\Attendance;

class RemindAttendance implements LoggableMessageInterface
{
    /** @var list<string> */
    private array $attendanceIds;

    public function __construct(string ...$attendanceIds)
    {
        $this->attendanceIds = array_values($attendanceIds);
    }

    /**
     * Restores the message from the payload the async transport stored.
     *
     * Because this method exists, PHP hands over the raw property array instead
     * of populating the object itself, so every property has to be assigned
     * here. Private property names arrive mangled as "\0<class>\0<property>",
     * hence the normalization below.
     *
     * The `attendanceId` fallback is a temporary BC shim, to be removed in a
     * future version: messages enqueued before reminders were grouped per
     * recipient were serialized on the async transport with a single readonly
     * `attendanceId` string; this promotes it to the new list so a reminder
     * still in the queue during a deploy resolves instead of failing. Remove
     * once the async queue can no longer hold a message from before that change
     * (i.e. after it has drained past the deploy that introduced grouping).
     *
     * @param array<array-key, mixed> $data
     */
    public function __unserialize(array $data): void
    {
        $properties = [];
        foreach ($data as $key => $value) {
            $key = (string) $key;
            $separator = strrpos($key, "\0");
            $properties[false === $separator ? $key : substr($key, $separator + 1)] = $value;
        }

        if (\is_array($ids = $properties['attendanceIds'] ?? null)) {
            $this->attendanceIds = array_values(array_filter($ids, \is_string(...)));

            return;
        }

        $legacy = $properties['attendanceId'] ?? null;
        $this->attendanceIds = \is_string($legacy) && '' !== $legacy ? [$legacy] : [];
    }

    /**
     * @return list<string>
     */
    public function getAttendanceIds(): array
    {
        return $this->attendanceIds;
    }

    public function getRelated(): array
    {
        return [
            Attendance::class => $this->attendanceIds,
        ];
    }
}
