<?php

declare(strict_types=1);

namespace App\Framework\LiveComponents\Attributes;

use Attribute;

/**
 * Marks a method as pollable for LiveComponents system.
 *
 * The method will be automatically called at specified intervals when attached to a component.
 *
 * Method Requirements:
 * - Must be public
 * - Return type must be serializable (array, SerializableState, scalar)
 * - Should be idempotent (safe to call multiple times)
 *
 * @example Basic polling
 * ```php
 * #[Poll(interval: 1000)]
 * public function checkNotifications(): array
 * {
 *     return ['count' => $this->notificationService->getUnreadCount()];
 * }
 * ```
 *
 * @example With event dispatch
 * ```php
 * #[Poll(interval: 5000, event: 'notifications.updated')]
 * public function pollNotifications(): NotificationState
 * {
 *     return $this->notificationService->getCurrentState();
 * }
 * ```
 */
#[Attribute(Attribute::TARGET_METHOD)]
final readonly class Poll
{
    /**
     * @param int $interval Polling interval in milliseconds (minimum: 100ms)
     * @param bool $enabled Whether polling is enabled by default
     * @param string|null $event Optional event name to dispatch on poll
     * @param bool $stopOnError Whether to stop polling if method throws exception
     */
    public function __construct(
        public int $interval = 1000,
        public bool $enabled = true,
        public ?string $event = null,
        public bool $stopOnError = false
    ) {
        if ($interval < 100) {
            throw new \InvalidArgumentException('Poll interval must be at least 100ms to prevent performance issues');
        }

        if ($interval > 300000) {
            throw new \InvalidArgumentException('Poll interval cannot exceed 5 minutes (300000ms)');
        }
    }

    /**
     * Get interval as Duration value object.
     */
    public function getInterval(): \App\Framework\Core\ValueObjects\Duration
    {
        return \App\Framework\Core\ValueObjects\Duration::fromMilliseconds($this->interval);
    }

    /**
     * Create new instance with different enabled state.
     */
    public function withEnabled(bool $enabled): self
    {
        return new self(
            interval: $this->interval,
            enabled: $enabled,
            event: $this->event,
            stopOnError: $this->stopOnError
        );
    }

    /**
     * Create new instance with different interval.
     */
    public function withInterval(int $interval): self
    {
        return new self(
            interval: $interval,
            enabled: $this->enabled,
            event: $this->event,
            stopOnError: $this->stopOnError
        );
    }
}
