<?php

namespace ServiceCore\Infrastructure\Service\Logger;

use ServiceCore\Domain\LoggerInterface;

abstract class BaseLogger implements LoggerInterface
{
    protected $delegateLogger;
    protected $serviceName;
    protected $traceDepth;
    protected $project;

    public static function createLogger(
        string $loggerClass,
        string $type = 'monolog',
        $stream = 'php://stdout',
        $serviceName = null,
        string $project = '',
        $traceDepth = 0
    ): BaseLogger {
        try {
            $logger = new $loggerClass();
            $logger->delegateLogger = LoggerFactory::build($type, $stream);
            $logger->serviceName = $serviceName;
            $logger->project = $project;
            $logger->traceDepth = $traceDepth;
            return $logger;
        } catch (\Exception $e) {
            throw new \Exception(sprintf("Unable to instantiate logger '%s'", $loggerClass));
        }
    }

    public function logDebug(string $messageTemplate, array $parameters = []): void
    {
        if ($this->delegateLogger->isDebugEnabled()) {
            $msg = $this->formatMessageTemplate('DEBUG', $messageTemplate);
            $this->delegateLogger->debug($msg, $parameters);
        }
    }

    public function logInfo(string $messageTemplate, array $parameters = []): void
    {
        if ($this->delegateLogger->isInfoEnabled()) {
            $msg = $this->formatMessageTemplate('INFO', $messageTemplate);
            $this->delegateLogger->info($msg, $parameters);
        }
    }

    public function logWarning(string $messageTemplate, array $parameters = []): void
    {
        if ($this->delegateLogger->isWarnEnabled()) {
            $msg = $this->formatMessageTemplate('WARNING', $messageTemplate);
            $this->delegateLogger->warning($msg, $parameters);
        }
    }

    public function logError(string $messageTemplate, array $parameters = []): void
    {
        if ($this->delegateLogger->isErrorEnabled()) {
            $msg = $this->formatMessageTemplate('ERROR', $messageTemplate);
            $this->delegateLogger->error($msg, $parameters);
        }
    }

    public function setLevel(int $logLevel): void
    {
        $this->delegateLogger->setLevel($logLevel);
    }

    public function isDebugEnabled(): bool
    {
        return $this->delegateLogger->isDebugEnabled();
    }

    public function isInfoEnabled(): bool
    {
        return $this->delegateLogger->isInfoEnabled();
    }

    public function isWarnEnabled(): bool
    {
        return $this->delegateLogger->isWarnEnabled();
    }

    public function isErrorEnabled(): bool
    {
        return $this->delegateLogger->isErrorEnabled();
    }

    public function formatMessageTemplate(string $mode, string $messageTemplate): string
    {
        $msg = sprintf("| %s | %s | %s | %s", $mode, $this->project, $this->serviceName, $messageTemplate);
        if ($this->traceDepth > 0) {
            $ex = new \Exception();
            $stackTrace = [];
            for ($i = 0; $i < $this->traceDepth; $i += 1) {
                try {
                    $curTrace = $ex->getTrace()[$i];

                    if (empty($curTrace['file']) && empty($curTrace['function']) && empty($curTrace['line'])) {
                        break;
                    }

                    $stackTrace[] = sprintf("%s.%s.%s", $curTrace['file'], $curTrace['function'], $curTrace['line']);
                } catch (\Throwable $t) {
                    break;
                }
            }
            $msg = sprintf("%s | %s", $msg, implode(" <= ", $stackTrace));
        }
        return $msg;
    }
}