<?php

declare(strict_types=1);

namespace apexl\Io\modules\logger\services;

use apexl\Io\modules\logger\dto\handlerConfig;
use apexl\Io\modules\logger\dto\handlerConfigCollection;
use apexl\Io\modules\logger\dto\handlerConfigParams\fileHandlerConfigParams;
use apexl\Io\modules\logger\dto\LoggerConfig;
use apexl\Io\modules\logger\dto\streamConfig;
use apexl\Io\modules\logger\enums\Handler;
use apexl\Io\modules\logger\interfaces\loggerInterface;
use Exception;

final class loggerStore
{
    final public const string DEFAULT__LOGGER_STREAM = 'default';
    final public const string DEFAULT__ERROR_STREAM = 'error';
    private const string DEFAULT__LOG_DIRECTORY = 'log';
    /** @var loggerInterface[] */
    private array $streams = [];

    public function __construct(private readonly loggerFactory $loggerFactory, private readonly LoggerConfig $config) {}

    /**
     * @throws Exception
     */
    public function logger(string $stream = self::DEFAULT__LOGGER_STREAM): loggerInterface
    {
        if ($this->getStreamConfig($stream) !== null) {
            if (!isset($this->streams[$stream])) {
                $this->streams[$stream] = $this->initStream($stream);
            }

            return $this->streams[$stream];
        }

        if (!$this->config->enableDynamicStreams) {
            error_log(sprintf('Unknown logger stream: %s', $stream), E_USER_WARNING);

            return $this->logger(self::DEFAULT__LOGGER_STREAM);
        }

        if (!isset($this->streams[$stream])) {
            $this->streams[$stream] = $this->loggerFactory->make(
                $stream,
                $this->dynamicStreamConfig($stream),
            );

            if ($this->config->warnAboutDynamicStreams && $stream !== self::DEFAULT__LOGGER_STREAM) {
                $this->logger(self::DEFAULT__LOGGER_STREAM)->warning(
                    'Dynamically created logger stream: {stream}',
                    ['stream' => $stream],
                );
            }
        }

        return $this->streams[$stream];
    }

    private function getStreamConfig(string $stream): ?streamConfig
    {
        return $this->config->streams[$stream] ?? null;
    }

    /**
     * @throws Exception
     */
    private function initStream(string $stream): loggerInterface
    {
        return $this->loggerFactory->make($stream, $this->getStreamConfig($stream));
    }

    private function dynamicStreamConfig(string $stream): streamConfig
    {
        return new streamConfig([
            'logDirectory' => self::DEFAULT__LOG_DIRECTORY,
            'level' => $this->config->level,
            'handlers' => new handlerConfigCollection([
                new handlerConfig([
                    'destination' => Handler::FILE->value,
                    'level' => $this->config->level,
                    'params' => new fileHandlerConfigParams([
                        'file' => sprintf('%s.log', $stream),
                    ]),
                ]),
            ]),
        ]);
    }
}
