<?php

namespace App\Framework\SyntaxHighlighter\Formatters;

use App\Framework\SyntaxHighlighter\Token;
use App\Framework\SyntaxHighlighter\TokenType;

class ConsoleFormatter implements FormatterInterface {
    private const string RESET = "\033[0m";
    private bool $useColors;

    public function __construct(?bool $useColors = null) {
        $this->useColors = $useColors ?? $this->isColorSupported();
    }

    public function format(array $tokens, array $options = []): string {
        $showLineNumbers = $options['lineNumbers'] ?? false;
        $startLine = $options['startLine'] ?? 1;
        $width = $options['width'] ?? 80;

        if (!$this->useColors) {
            return $this->formatPlainText($tokens, $showLineNumbers, $startLine);
        }

        $lines = $this->groupTokensByLines($tokens);
        $output = [];
        $lineNumberWidth = strlen((string) (count($lines) + $startLine - 1));

        foreach ($lines as $lineNumber => $lineTokens) {
            $actualLineNumber = $lineNumber + $startLine - 1;
            $lineContent = $this->formatLine($lineTokens);

            if ($showLineNumbers) {
                $lineNumberStr = str_pad($actualLineNumber, $lineNumberWidth, ' ', STR_PAD_LEFT);
                $output[] = "\033[90m{$lineNumberStr}\033[0m │ {$lineContent}";
            } else {
                $output[] = $lineContent;
            }
        }

        return implode("\n", $output);
    }

    /*private function isColorSupported(): bool {
        return DIRECTORY_SEPARATOR === '/' &&
               function_exists('posix_isatty') &&
               posix_isatty(STDOUT);
    }*/

    private function groupTokensByLines(array $tokens): array {
        $lines = [];
        $currentLine = 1;

        foreach ($tokens as $token) {
            if (!isset($lines[$currentLine])) {
                $lines[$currentLine] = [];
            }

            if (str_contains($token->value, "\n")) {
                $parts = explode("\n", $token->value);
                for ($i = 0; $i < count($parts); $i++) {
                    if ($i > 0) {
                        $currentLine++;
                        if (!isset($lines[$currentLine])) {
                            $lines[$currentLine] = [];
                        }
                    }
                    if ($parts[$i] !== '') {
                        $lines[$currentLine][] = new Token(
                            $token->type,
                            $parts[$i],
                            $currentLine,
                            $token->column
                        );
                    }
                }
            } else {
                $lines[$currentLine][] = $token;
            }
        }

        return $lines;
    }

    private function formatLine(array $tokens): string {
        $content = '';

        foreach ($tokens as $token) {
            $content .= $this->formatToken($token);
        }

        return $content . self::RESET;
    }

    private function formatToken(Token $token): string {
        if ($token->type === TokenType::WHITESPACE) {
            return $token->value;
        }

        $color = $token->type->getConsoleColor();
        return $color . $token->value . self::RESET;
    }

    private function formatPlainText(array $tokens, bool $showLineNumbers, int $startLine): string {
        $content = '';
        $lineNumber = $startLine;
        $atLineStart = true;

        foreach ($tokens as $token) {
            if ($atLineStart && $showLineNumbers) {
                $content .= sprintf('%3d: ', $lineNumber);
                $atLineStart = false;
            }

            $content .= $token->value;

            if (str_contains($token->value, "\n")) {
                $lineNumber += substr_count($token->value, "\n");
                $atLineStart = true;
            }
        }

        return $content;
    }
}
