<?php

namespace onespace\core\modules\metrics\actions;

use onespace\core\components\MetricsCollectorInterface;
use onespace\core\components\MetricsComponent;
use Prometheus\RenderTextFormat;
use Yii;
use yii\base\Action;
use yii\base\InvalidConfigException;
use yii\web\Response;

/**
 * Runs every configured collector against the app's Prometheus registry,
 * then renders it in the standard text exposition format.
 *
 * This is a plain yii\base\Action, not tied to any particular controller -
 * it's used by MetricsController::actions() by default, but can just as
 * easily be attached to any other controller:
 *
 * ```php
 * public function actions(): array
 * {
 *     return [
 *         'metrics' => [
 *             'class' => \onespace\core\modules\metrics\actions\MetricsAction::class,
 *             'collectors' => [\onespace\core\components\QueueMetricsCollector::class],
 *         ],
 *     ];
 * }
 * ```
 *
 * @psalm-api
 *
 * @template-extends Action<\yii\web\Controller>
 */
class MetricsAction extends Action
{
    /** @var string application component ID for the Prometheus registry */
    public string $metricsComponent = 'metrics';

    /**
     * @var array<class-string<MetricsCollectorInterface>|MetricsCollectorInterface|array>
     * Collectors run, in declared order, at scrape time before the registry
     * is rendered. Each entry may be a class name, a Yii config array (with
     * a `class` key), or an already-built MetricsCollectorInterface instance.
     */
    public array $collectors = [];

    public function run(): Response
    {
        /** @var MetricsComponent $metrics */
        $metrics = Yii::$app->get($this->metricsComponent);

        foreach ($this->collectors as $collector) {
            $instance = $collector instanceof MetricsCollectorInterface
                ? $collector
                : Yii::createObject($collector);

            if (!$instance instanceof MetricsCollectorInterface) {
                throw new InvalidConfigException(
                    (is_object($instance) ? get_class($instance) : (string) $collector)
                    . ' must implement ' . MetricsCollectorInterface::class
                );
            }

            $instance->collect($metrics);
        }

        $renderer = new RenderTextFormat();
        $body = $renderer->render($metrics->getRegistry()->getMetricFamilySamples());

        $response = Yii::$app->response;
        $response->format = Response::FORMAT_RAW;
        $response->headers->set('Content-Type', RenderTextFormat::MIME_TYPE);
        $response->content = $body;

        return $response;
    }
}