<?php

declare(strict_types=1);

namespace App\Framework\Console\Components;

use App\Framework\Console\ConsoleColor;
use App\Framework\Console\ConsoleStyle;

/**
 * Rendert eine Textbox in der Konsole.
 */
final readonly class TextBox
{
    public function __construct(
        private string        $content,
        private int           $width = 80,
        private int           $padding = 1,
        private ?ConsoleStyle $borderStyle = null,
        private ?ConsoleStyle $contentStyle = null,
        private ?string       $title = null
    ) {
    }

    public function render(): string
    {
        $borderStyle = $this->borderStyle ?? ConsoleStyle::create(color: ConsoleColor::GRAY);
        $contentStyle = $this->contentStyle ?? ConsoleStyle::create();

        $contentWidth = $this->width - ($this->padding * 2) - 2;
        $lines = $this->wrapText($this->content, $contentWidth);
        $output = '';

        // Obere Linie
        if ($this->title) {
            $titleLength = mb_strlen($this->title);
            $availableSpace = $this->width - $titleLength - 6; // Abzug für '[ ]' und Ränder
            $leftPadding = max(0, (int)floor($availableSpace / 2));
            $rightPadding = max(0, $availableSpace - $leftPadding);

            $output .= $borderStyle->apply('┌' . str_repeat('─', $leftPadding) . '[ ' . $this->title . ' ]' . str_repeat('─', $rightPadding) . '┐') . "\n";
        } else {
            $output .= $borderStyle->apply('┌' . str_repeat('─', $this->width - 2) . '┐') . "\n";
        }

        // Padding oben
        for ($i = 0; $i < $this->padding; $i++) {
            $output .= $borderStyle->apply('│') . str_repeat(' ', $this->width - 2) . $borderStyle->apply('│') . "\n";
        }

        // Inhalt
        foreach ($lines as $line) {
            $lineLength = mb_strlen($line);
            $spaces = $contentWidth - $lineLength;
            $paddedLine = $line . str_repeat(' ', $spaces);

            $output .= $borderStyle->apply('│') .
                      str_repeat(' ', $this->padding) .
                      $contentStyle->apply($paddedLine) .
                      str_repeat(' ', $this->padding) .
                      $borderStyle->apply('│') . "\n";
        }

        // Padding unten
        for ($i = 0; $i < $this->padding; $i++) {
            $output .= $borderStyle->apply('│') . str_repeat(' ', $this->width - 2) . $borderStyle->apply('│') . "\n";
        }

        // Untere Linie
        $output .= $borderStyle->apply('└' . str_repeat('─', $this->width - 2) . '┘') . "\n";

        return $output;
    }

    private function wrapText(string $text, int $width): array
    {
        $lines = explode("\n", $text);
        $wrapped = [];

        foreach ($lines as $line) {
            if (mb_strlen($line) <= $width) {
                $wrapped[] = $line;
            } else {
                $wrapped = array_merge($wrapped, $this->splitTextIntoLines($line, $width));
            }
        }

        // Leere Zeile hinzufügen, falls keine Inhalte vorhanden
        if (empty($wrapped)) {
            $wrapped[] = '';
        }

        return $wrapped;
    }

    private function splitTextIntoLines(string $text, int $width): array
    {
        $lines = [];
        $words = explode(' ', $text);
        $currentLine = '';

        foreach ($words as $word) {
            $testLine = empty($currentLine) ? $word : $currentLine . ' ' . $word;

            if (mb_strlen($testLine) <= $width) {
                $currentLine = $testLine;
            } else {
                if (! empty($currentLine)) {
                    $lines[] = $currentLine;
                    $currentLine = $word;
                } else {
                    // Wort ist länger als die Zeile - hart umbrechen
                    $lines[] = mb_substr($word, 0, $width);
                    $currentLine = mb_substr($word, $width);
                }
            }
        }

        if (! empty($currentLine)) {
            $lines[] = $currentLine;
        }

        return $lines ?: [''];
    }
}
