<?php

declare(strict_types=1);

namespace Apexl\Io\Logger\Services\HandlerCreator;

use Apexl\Io\Logger\Dtos\HandlerConfig;
use Apexl\Io\Logger\Dtos\HandlerConfigParams\SlackHandlerConfigParams;
use Apexl\Io\Logger\Dtos\StreamConfig;
use Monolog\Handler\HandlerInterface;
use Monolog\Handler\NullHandler;
use Monolog\Handler\SlackWebhookHandler;

/**
 * Posts records to a Slack channel through an incoming webhook.
 *
 * Monolog also ships SlackHandler, which talks to the Slack API over a raw socket
 * with a bot token. The webhook is the one to use: no token to scope or rotate, no
 * socket to keep open, and the URL itself carries the channel.
 */
final readonly class SlackLogHandlerCreator extends HandlerCreator
{
    public function create(
        string $streamName,
        HandlerConfig $handlerConfig,
        StreamConfig $streamConfig
    ): HandlerInterface {
        /** @var SlackHandlerConfigParams $params */
        $params = $handlerConfig->params;
        $level = $this->level($handlerConfig, $streamConfig);

        if (!$params->webhook_url) {
            error_log(
                sprintf(
                    'The \'slack\' log handler on stream \'%s\' has no `webhook_url`; not posting',
                    $streamName
                )
            );

            return new NullHandler();
        }

        // SlackWebhookHandler throws without ext-curl, which would be thrown while the
        // logger is still being built and so would take down whatever was being logged
        // about. Logging failing must never be worse than the thing it was reporting.
        if (!extension_loaded('curl')) {
            error_log(
                sprintf(
                    'The \'slack\' log handler on stream \'%s\' needs ext-curl; not posting',
                    $streamName
                )
            );

            return new NullHandler();
        }

        // Deliberately not wrapped in a BufferHandler, unlike the mail handler. Buffering
        // there turns a run into one email; here it would not merge anything, because
        // handleBatch() posts one message per record either way — it would only delay
        // them, and then release the whole backlog at once. Volume is controlled by the
        // level instead, which is why this belongs on error and above.
        return new SlackWebhookHandler(
            $params->webhook_url,
            $params->channel,
            $params->username,
            $params->use_attachment,
            $params->icon_emoji,
            $params->short_attachment,
            $params->include_context,
            $level,
            true,
            $params->exclude_fields,
        );
    }
}
