<?php
/**
 * Custom Line Formatter for CloudXM Logger v2.0
 *
 * Extends Monolog's LineFormatter to automatically format context arrays as pretty-printed JSON
 * in debug.log output for better readability.
 */

namespace CloudXM\SDK\Utilities;

use Monolog\Formatter\LineFormatter;

class CustomLineFormatter extends LineFormatter
{
    public function format(\Monolog\LogRecord $record): string
    {
        // Get the standard formatted line
        $output = parent::format($record);

        // If context exists and is not empty, append compact bracket format on same line
        if (!empty($record['context'])) {
            $formattedContext = $this->formatContextRecursively($record['context']);
            $contextString = $this->formatContextAsString($formattedContext);
            // Remove trailing newline from parent format and append context on same line
            $output = rtrim($output, "\n") . " " . $contextString . "\n";
        }

        return $output;
    }

    /**
     * Recursively format context, detecting and handling JSON strings
     */
    private function formatContextRecursively(array $context): array
    {
        $formatted = [];

        foreach ($context as $key => $value) {
            if (is_string($value) && $this->isJsonString($value)) {
                // Try to decode JSON strings for better nesting
                $decoded = json_decode($value, true);
                if ($decoded !== null) {
                    $formatted[$key] = $decoded;
                } else {
                    $formatted[$key] = $value;
                }
            } elseif (is_array($value)) {
                $formatted[$key] = $this->formatContextRecursively($value);
            } else {
                $formatted[$key] = $value;
            }
        }

        return $formatted;
    }

    /**
     * Format context array as compact bracket notation string
     */
    private function formatContextAsString(array $context): string
    {
        $parts = [];
        foreach ($context as $key => $value) {
            $formattedValue = $this->formatValue($value);
            $parts[] = "$key=$formattedValue";
        }
        return '[' . implode(', ', $parts) . ']';
    }

    /**
     * Format individual values for compact display
     */
    private function formatValue($value): string
    {
        if (is_array($value)) {
            if (empty($value)) {
                return '{}';
            }
            $pairs = [];
            foreach ($value as $k => $v) {
                $pairs[] = "$k=" . $this->formatValue($v);
            }
            return '{' . implode(', ', $pairs) . '}';
        } elseif (is_bool($value)) {
            return $value ? 'true' : 'false';
        } elseif (is_null($value)) {
            return 'null';
        } elseif (is_string($value)) {
            // Escape quotes and limit string length for readability
            $escaped = addslashes($value);
            if (strlen($escaped) > 100) {
                $escaped = substr($escaped, 0, 97) . '...';
            }
            return '"' . $escaped . '"';
        } elseif (is_object($value)) {
            // Handle objects by showing class name to avoid conversion errors
            return get_class($value) . '()';
        } else {
            return (string)$value;
        }
    }

    /**
     * Check if a string contains valid JSON
     */
    private function isJsonString(string $string): bool
    {
        // Quick check: must start with { or [ and end with } or ]
        $trimmed = trim($string);
        if (empty($trimmed)) {
            return false;
        }

        $first = $trimmed[0];
        $last = $trimmed[strlen($trimmed) - 1];

        if (!(($first === '{' && $last === '}') || ($first === '[' && $last === ']'))) {
            return false;
        }

        // Try to decode
        json_decode($trimmed, true);
        return json_last_error() === JSON_ERROR_NONE;
    }
}