<?php

namespace onespace\core\components;

use Yii;
use yii\base\Component;
use Prometheus\CollectorRegistry;
use Prometheus\Storage\Redis;

/**
 * @psalm-api
 */
class MetricsComponent extends Component {
    public string $redisHost = 'redis_metrics';
    public int $redisPort = 6379;
    public float $redisTimeout = 0.1;

    /**
     * @var string|null Passed through to the underlying \Redis::auth() call
     * (see Prometheus\Storage\RedisClients\PHPRedis::ensureOpenConnection())
     * only when non-null. Leave unset for a Redis instance with no
     * `requirepass` configured.
     */
    public ?string $redisPassword = null;

    public string $namespace = '';


    /** @psalm-suppress PropertyNotSetInConstructor - Set in init */
    private CollectorRegistry $registry;

    #[\Override]
    public function init(): void {
        parent::init();

        if ($this->namespace === '') {
            $this->namespace = Yii::$app->name;
            $this->namespace = preg_replace('/[^a-zA-Z0-9_]/', '_', $this->namespace) ?? throw new \Exception("Failed to resolve namespace");
        }

        Redis::setDefaultOptions([
            'host' => $this->redisHost,
            'port' => $this->redisPort,
            'timeout' => $this->redisTimeout,
            'read_timeout' => '10',
            'persistent_connections' => false,
            // Safe to pass through unconditionally - the client library
            // uses isset() to decide whether to authenticate, and isset()
            // on a null value is false, so a null password is a no-op.
            'password' => $this->redisPassword,
        ]);

        $this->registry = new CollectorRegistry(new Redis());
    }

    /**
     * @param string $name Name of Counter instance
     * @param string help e.g. The number of requests made.
     * @param string[] $labelNames e.g. ['controller', 'action']
     * @see \Prometheus\CollectorRegistry::getOrRegisterCounter()
     */
    public function counter(
        string $name,
        string $help,
        array $labelNames = []
    ): \Prometheus\Counter {
        return $this->registry->getOrRegisterCounter(
            $this->namespace,
            $name,
            $help,
            $labelNames
        );
    }

    /**
     * @param string $name Name of Counter instance
     * @param string help e.g. The number of requests made.
     * @param string[] $labelNames e.g. ['controller', 'action']
     * @see \Prometheus\CollectorRegistry::getOrRegisterGauge()
     */
    public function gauge(
        string $name,
        string $help,
        array $labelNames = []
    ): \Prometheus\Gauge {
        return $this->registry->getOrRegisterGauge(
            $this->namespace,
            $name,
            $help,
            $labelNames
        );
    }

    /**
     * @param string $name Name of Counter instance
     * @param string help e.g. The number of requests made.
     * @param string[] $labelNames e.g. ['controller', 'action']
     * @param float[]|null $buckets
     * @see \Prometheus\CollectorRegistry::getOrRegisterHistogram()
     */
    public function histogram(
        string $name,
        string $help,
        array $labelNames = [],
        array|null $buckets = null
    ): \Prometheus\Histogram {
        return $this->registry->getOrRegisterHistogram(
            $this->namespace,
            $name,
            $help,
            $labelNames,
            $buckets
        );
    }

    public function getRegistry(): CollectorRegistry {
        return $this->registry;
    }
}