<?php

declare(strict_types=1);

namespace App\Framework\ErrorBoundaries\Events;

use App\Framework\EventBus\EventBus;
use App\Framework\Logging\Logger;

/**
 * Publisher for error boundary events
 */
final readonly class BoundaryEventPublisher
{
    public function __construct(
        private ?EventBus $eventBus = null,
        private ?Logger $logger = null,
    ) {
    }

    /**
     * Publish boundary event
     */
    public function publish(BoundaryEventInterface $event): void
    {
        // Log the event
        $this->logEvent($event);

        // Publish to event bus if available
        if ($this->eventBus !== null) {
            $this->eventBus->dispatch($event);
        }
    }

    /**
     * Publish execution success event
     */
    public function publishExecutionSucceeded(BoundaryExecutionSucceeded $event): void
    {
        $this->publish($event);
    }

    /**
     * Publish execution failure event
     */
    public function publishExecutionFailed(BoundaryExecutionFailed $event): void
    {
        $this->publish($event);
    }

    /**
     * Publish fallback execution event
     */
    public function publishFallbackExecuted(BoundaryFallbackExecuted $event): void
    {
        $this->publish($event);
    }

    /**
     * Publish circuit breaker tripped event
     */
    public function publishCircuitBreakerTripped(BoundaryCircuitBreakerTripped $event): void
    {
        $this->publish($event);
    }

    /**
     * Publish circuit breaker recovered event
     */
    public function publishCircuitBreakerRecovered(BoundaryCircuitBreakerRecovered $event): void
    {
        $this->publish($event);
    }

    /**
     * Publish timeout event
     */
    public function publishTimeoutOccurred(BoundaryTimeoutOccurred $event): void
    {
        $this->publish($event);
    }

    /**
     * Batch publish multiple events
     */
    public function publishBatch(array $events): void
    {
        foreach ($events as $event) {
            if ($event instanceof BoundaryEventInterface) {
                $this->publish($event);
            }
        }
    }

    private function logEvent(BoundaryEventInterface $event): void
    {
        if ($this->logger === null) {
            return;
        }

        $context = [
            'event_id' => $event->getEventId(),
            'boundary_name' => $event->boundaryName,
            'event_type' => $event->eventType,
            'occurred_at' => $event->occurredAt->toIsoString(),
            'should_alert' => $event->shouldAlert(),
            'event_data' => $event->toArray(),
        ];

        $logMessage = "[ErrorBoundary Event] {$event->eventType} for boundary '{$event->boundaryName}'";

        if ($event->message !== null) {
            $logMessage .= ": {$event->message}";
        }

        match ($event->severity) {
            'debug' => $this->logger->debug($logMessage, $context),
            'info' => $this->logger->info($logMessage, $context),
            'warning' => $this->logger->warning($logMessage, $context),
            'error' => $this->logger->error($logMessage, $context),
            'critical' => $this->logger->error($logMessage, $context), // Map critical to error
            default => $this->logger->info($logMessage, $context),
        };
    }
}
