<?php

declare(strict_types=1);

namespace App\Framework\Webhook\Sending;

use App\Framework\Logging\Logger;
use App\Framework\Queue\Queue;
use App\Framework\Webhook\Jobs\WebhookJob;
use App\Framework\Webhook\ValueObjects\WebhookPayload;
use App\Framework\Webhook\ValueObjects\WebhookProvider;
use DateTimeImmutable;

/**
 * Webhook scheduler using framework's Queue system
 * Manages async webhook delivery with priority and scheduling
 */
final readonly class WebhookScheduler
{
    public function __construct(
        private Queue $queue,
        private Logger $logger
    ) {
    }

    /**
     * Schedule webhook for immediate delivery
     */
    public function send(
        string $url,
        WebhookPayload $payload,
        WebhookProvider $provider,
        string $secret,
        array $options = []
    ): string {
        $job = WebhookJob::immediate($url, $payload, $provider, $secret, $options);

        $this->queue->push($job);

        $jobId = $job->getJobId();

        $this->logger->info('Webhook scheduled for immediate delivery', [
            'job_id' => $jobId,
            'url' => $url,
            'provider' => $provider->toString(),
            'priority' => $job->getPriority(),
        ]);

        return $jobId;
    }

    /**
     * Schedule webhook for future delivery
     */
    public function sendAt(
        string $url,
        WebhookPayload $payload,
        WebhookProvider $provider,
        string $secret,
        DateTimeImmutable $scheduledAt,
        array $options = []
    ): string {
        $job = WebhookJob::delayed($url, $payload, $provider, $secret, $scheduledAt, $options);

        $this->queue->push($job);

        $jobId = $job->getJobId();

        $this->logger->info('Webhook scheduled for future delivery', [
            'job_id' => $jobId,
            'url' => $url,
            'provider' => $provider->toString(),
            'scheduled_at' => $scheduledAt->format('c'),
            'delay_seconds' => $scheduledAt->getTimestamp() - time(),
        ]);

        return $jobId;
    }

    /**
     * Schedule webhook with delay in seconds
     */
    public function sendIn(
        string $url,
        WebhookPayload $payload,
        WebhookProvider $provider,
        string $secret,
        int $delaySeconds,
        array $options = []
    ): string {
        $scheduledAt = (new DateTimeImmutable())->modify("+{$delaySeconds} seconds");

        return $this->sendAt($url, $payload, $provider, $secret, $scheduledAt, $options);
    }

    /**
     * Schedule high priority webhook
     */
    public function sendUrgent(
        string $url,
        WebhookPayload $payload,
        WebhookProvider $provider,
        string $secret,
        array $options = []
    ): string {
        $options['priority'] = 10; // High priority

        return $this->send($url, $payload, $provider, $secret, $options);
    }

    /**
     * Schedule webhook with custom retry configuration
     */
    public function sendWithRetries(
        string $url,
        WebhookPayload $payload,
        WebhookProvider $provider,
        string $secret,
        int $maxRetries,
        array $options = []
    ): string {
        $options['max_retries'] = $maxRetries;

        return $this->send($url, $payload, $provider, $secret, $options);
    }

    /**
     * Bulk schedule multiple webhooks
     */
    public function sendBulk(array $webhooks): array
    {
        $jobIds = [];

        foreach ($webhooks as $webhook) {
            $jobId = $this->send(
                url: $webhook['url'],
                payload: $webhook['payload'],
                provider: $webhook['provider'],
                secret: $webhook['secret'],
                options: $webhook['options'] ?? []
            );

            $jobIds[] = $jobId;
        }

        $this->logger->info('Bulk webhooks scheduled', [
            'count' => count($webhooks),
            'job_ids' => $jobIds,
        ]);

        return $jobIds;
    }

    /**
     * Schedule webhook with specific event data
     */
    public function sendEvent(
        string $url,
        string $eventType,
        array $eventData,
        WebhookProvider $provider,
        string $secret,
        array $options = []
    ): string {
        $payload = WebhookPayload::create($eventData, $eventType);

        return $this->send($url, $payload, $provider, $secret, $options);
    }

    /**
     * Get queue statistics for monitoring
     */
    public function getQueueStats(): array
    {
        // This would depend on the queue implementation
        // For now, return basic info
        return [
            'queue_type' => get_class($this->queue),
            'timestamp' => (new DateTimeImmutable())->format('c'),
        ];
    }
}
