<?php

declare(strict_types=1);

namespace Butschster\ContextGenerator\Application\Logger;

use Psr\Log\AbstractLogger;
use Psr\Log\LogLevel as PsrLogLevel;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * PSR-3 compatible console logger that outputs to a Symfony Console OutputInterface.
 * Respects the verbosity levels of the Console component.
 */
final class ConsoleLogger extends AbstractLogger implements HasPrefixLoggerInterface
{
    public function __construct(
        private readonly OutputInterface $output,
        private readonly FormatterInterface $formatter = new SimpleFormatter(),
    ) {}

    public function withPrefix(string $prefix): static
    {
        return new self($this->output, $this->formatter->withPrefix($prefix));
    }

    public function getPrefix(): string
    {
        return $this->formatter->getPrefix();
    }

    public function log($level, string|\Stringable $message, array $context = []): void
    {
        $logLevel = $this->normalizeLogLevel($level);

        // Only output if verbosity of the output is sufficient for this log level
        if (!$this->isLevelEnabled($logLevel)) {
            return;
        }

        $formattedMessage = $this->formatter->format($logLevel, $message, $context);

        // Apply color formatting based on log level
        $colorizedMessage = $this->colorize($formattedMessage, $logLevel);

        $this->output->writeln($colorizedMessage);
    }

    /**
     * Check if the log level is enabled for the current output verbosity.
     */
    private function isLevelEnabled(string $level): bool
    {
        $verbosity = $this->output->getVerbosity();

        return match ($level) {
            PsrLogLevel::EMERGENCY,
            PsrLogLevel::ALERT,
            PsrLogLevel::CRITICAL,
            PsrLogLevel::ERROR => true, // Always show errors

            PsrLogLevel::WARNING,
            PsrLogLevel::NOTICE => $verbosity >= OutputInterface::VERBOSITY_NORMAL,

            PsrLogLevel::INFO => $verbosity >= OutputInterface::VERBOSITY_VERY_VERBOSE,

            PsrLogLevel::DEBUG => $verbosity >= OutputInterface::VERBOSITY_DEBUG,

            default => false,
        };
    }

    /**
     * Apply color formatting based on log level.
     */
    private function colorize(string $message, string $level): string
    {
        $color = LogLevel::fromString($level)->getAnsiColor();

        if (empty($color)) {
            return $message;
        }

        return "{$color}{$message}\033[0m";
    }

    /**
     * Convert any valid log level to a normalized string.
     */
    private function normalizeLogLevel(mixed $level): string
    {
        if (\is_string($level)) {
            return \strtolower($level);
        }

        if ($level instanceof \Stringable) {
            return \strtolower((string) $level);
        }

        // Default to 'info' for invalid levels
        return PsrLogLevel::INFO;
    }
}
