<?php

/**
 * @package   bdk/debug
 * @author    Brad Kent <bkfake-github@yahoo.com>
 * @license   http://opensource.org/licenses/MIT MIT
 * @copyright 2014-2025 Brad Kent
 * @since     2.3
 */

namespace bdk\Debug\Dump;

use bdk\Debug;
use bdk\Debug\Dump\TextAnsi\Value;
use bdk\Debug\LogEntry;

/**
 * Output log entries as ANSI text
 */
class TextAnsi extends Text
{
    const ESCAPE_RESET = "\x00escapeReset\x00";

    /** @var array<string,mixed> */
    protected $ansiCfg = array(
        'escapeCodes' => array(
            'arrayKey' => "\e[38;5;83m",    // yellow
            'binary' => "\e[30;48;5;250m",  // black foreground / grey background
            'char' => "\e[34;48;5;14m",     // blue foreground / light-blue background
            'excluded' => "\e[38;5;9m",     // red
            'false' => "\e[91m",            // red
            'keyword' => "\e[38;5;45m",     // blue
            'maxlen' => "\e[30;48;5;41m",   // black foreground / light-green background
            'muted' => "\e[38;5;250m",      // dark grey
            'numeric' => "\e[96m",          // blue
            'operator' => "\e[38;5;224m",   // "misty rose"
            'property' => "\e[38;5;83m",    // yellow
            'punct' => "\e[38;5;245m",      // grey  (brackets)
            'quote' => "\e[38;5;250m",      // grey
            'recursion' => "\e[38;5;196m",  // red
            'true' => "\e[32m",             // green
        ),
        'escapeCodesLevels' => array(
            'error' => "\e[38;5;88;48;5;203;1;4m",
            'info' => "\e[38;5;55;48;5;159;1;4m",
            'success' => "\e[38;5;22;48;5;121;1;4m",
            'warn' => "\e[38;5;1;48;5;230;1;4m",
        ),
        'escapeCodesMethods' => array(
            'error' => "\e[38;5;9m",
            'info' => "\e[38;5;159m",
            'warn' => "\e[38;5;148m",
        ),
        'glue' => array(
            'equal' => " \e[38;5;245m=\x00escapeReset\x00 ",
            'multiple' => "\e[38;5;245m, \x00escapeReset\x00",
        ),
        'stream' => 'php://stderr',   // filepath/uri/resource
    );

    /**
     * Constructor
     *
     * @param Debug $debug Debug Instance
     */
    public function __construct(Debug $debug)
    {
        $this->cfg = $debug->arrayUtil->mergeDeep($this->cfg, $this->ansiCfg);
        parent::__construct($debug);
    }

    /**
     * Return log entry as text
     *
     * @param LogEntry $logEntry LogEntry instance
     *
     * @return string
     */
    public function processLogEntry(LogEntry $logEntry)
    {
        $escapeCode = $this->logEntryEscapeCode($logEntry);
        $escapeResetDefault = "\e[0m";
        $escapeReset = $escapeCode ?: $escapeResetDefault;
        $this->valDumper->escapeReset = $escapeReset;
        $str = parent::processLogEntry($logEntry);
        $str = \str_replace(self::ESCAPE_RESET, $escapeReset, $str);
        if ($escapeCode) {
            $strIndent = \str_repeat('    ', $this->depth);
            $str = \preg_replace('#^(' . $strIndent . ')(.+)$#m', '$1' . $escapeCode . '$2' . $escapeResetDefault, $str);
            $this->valDumper->escapeReset = $escapeResetDefault;
        }
        return $str;
    }

    /**
     * Get value dumper
     *
     * @return \bdk\Debug\Dump\BaseValue
     */
    protected function getValDumper()
    {
        if (!$this->valDumper) {
            $this->valDumper = new Value($this);
            $this->valDumper->setCfg($this->cfg);
        }
        return $this->valDumper;
    }

    /**
     * Get the ansi escape code for the logEntry's method
     *
     * @param LogEntry $logEntry LogEntry instance
     *
     * @return string ansi escape sequence
     */
    private function logEntryEscapeCode(LogEntry $logEntry)
    {
        $method = $logEntry['method'];
        $escapeCode = '';
        if ($method === 'alert') {
            $level = $logEntry->getMeta('level');
            $escapeCode = $this->cfg['escapeCodesLevels'][$level];
        } elseif (isset($this->cfg['escapeCodesMethods'][$method])) {
            $escapeCode = $this->cfg['escapeCodesMethods'][$method];
        } elseif ($method === 'groupSummary' || $logEntry->getMeta('closesSummary')) {
            $escapeCode = "\e[2m";
        }
        return $escapeCode;
    }
}
