<?php

declare(strict_types=1);

namespace App\Services\Alerts;

use App\Jobs\Alerts\DeliverAlertsJob;
use App\Models\AlertDelivery;
use App\Models\AlertDestination;
use App\Models\User;
use App\Services\Audit\WorkspaceAuditLogger;
use App\Support\Audit\AuditActionId;
use Illuminate\Auth\Access\AuthorizationException;

class AlertDestinationTestMessageService
{
    private const int RATE_LIMIT_SECONDS = 60;

    public function __construct(
        private WorkspaceAuditLogger $auditLogger,
    ) {}

    /**
     * Send a test message for the given alert destination.
     *
     * @return array{success: bool, message: string, delivery_id: int|null}
     */
    public function sendTest(AlertDestination $destination, User $actor): array
    {
        if (! $actor->can('update', $destination)) {
            throw new AuthorizationException('You do not have permission to send test messages for this destination.');
        }

        if (! $destination->is_enabled) {
            return [
                'success' => false,
                'message' => 'This destination is currently disabled. Enable it before sending a test message.',
                'delivery_id' => null,
            ];
        }

        if ($this->isRateLimited($destination)) {
            return [
                'success' => false,
                'message' => 'A test message was sent recently. Please wait before trying again.',
                'delivery_id' => null,
            ];
        }

        $delivery = $this->createTestDelivery($destination);

        $this->auditLog($destination, $actor);

        DeliverAlertsJob::dispatch((int) $destination->workspace_id);

        return [
            'success' => true,
            'message' => 'Test message queued for delivery.',
            'delivery_id' => (int) $delivery->getKey(),
        ];
    }

    private function isRateLimited(AlertDestination $destination): bool
    {
        return AlertDelivery::query()
            ->where('workspace_id', (int) $destination->workspace_id)
            ->where('alert_destination_id', (int) $destination->getKey())
            ->where('event_type', AlertDelivery::EVENT_TYPE_TEST)
            ->where('created_at', '>=', now()->subSeconds(self::RATE_LIMIT_SECONDS))
            ->exists();
    }

    private function createTestDelivery(AlertDestination $destination): AlertDelivery
    {
        return AlertDelivery::create([
            'workspace_id' => (int) $destination->workspace_id,
            'managed_environment_id' => null,
            'alert_rule_id' => null,
            'alert_destination_id' => (int) $destination->getKey(),
            'event_type' => AlertDelivery::EVENT_TYPE_TEST,
            'status' => AlertDelivery::STATUS_QUEUED,
            'severity' => null,
            'fingerprint_hash' => 'test:'.(int) $destination->getKey(),
            'attempt_count' => 0,
            'payload' => [
                'title' => 'Test alert',
                'body' => 'This is a test delivery for destination verification.',
            ],
        ]);
    }

    private function auditLog(AlertDestination $destination, User $actor): void
    {
        $workspace = $destination->workspace;

        if ($workspace === null) {
            return;
        }

        $this->auditLogger->log(
            workspace: $workspace,
            action: AuditActionId::AlertDestinationTestRequested->value,
            context: [
                'metadata' => [
                    'alert_destination_id' => (int) $destination->getKey(),
                    'name' => (string) $destination->name,
                    'type' => (string) $destination->type,
                ],
            ],
            actor: $actor,
            resourceType: 'alert_destination',
            resourceId: (string) $destination->getKey(),
        );
    }
}
