<?php
declare(strict_types=1);

namespace App\Framework\Console\Components;

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

/**
 * Rendert eine Tabelle in der Konsole.
 */
final class Table
{
    private array $headers = [];
    private array $rows = [];
    private array $columnWidths = [];
    private int $padding = 1;

    public function __construct(
        private ?ConsoleStyle $headerStyle = null,
        private ?ConsoleStyle $rowStyle = null,
        private ?ConsoleStyle $borderStyle = null,
        private bool $showBorders = true
    ) {
        $this->headerStyle ??= ConsoleStyle::create(color: ConsoleColor::BRIGHT_WHITE, format: ConsoleFormat::BOLD);
        $this->rowStyle ??= ConsoleStyle::create();
        $this->borderStyle ??= ConsoleStyle::create(color: ConsoleColor::GRAY);
    }

    /**
     * Setzt die Spaltenüberschriften der Tabelle.
     */
    public function setHeaders(array $headers): self
    {
        $this->headers = $headers;
        $this->calculateColumnWidths();
        return $this;
    }

    /**
     * Fügt eine Zeile zur Tabelle hinzu.
     */
    public function addRow(array $row): self
    {
        $this->rows[] = $row;
        $this->calculateColumnWidths();
        return $this;
    }

    /**
     * Setzt alle Zeilen der Tabelle.
     */
    public function setRows(array $rows): self
    {
        $this->rows = $rows;
        $this->calculateColumnWidths();
        return $this;
    }

    /**
     * Setzt den Innenabstand der Zellen.
     */
    public function setPadding(int $padding): self
    {
        $this->padding = max(0, $padding);
        return $this;
    }

    /**
     * Rendert die Tabelle und gibt den Text zurück.
     */
    public function render(): string
    {
        if (empty($this->headers) && empty($this->rows)) {
            return '';
        }

        $output = '';

        if ($this->showBorders) {
            $output .= $this->renderBorder('top') . "\n";
        }

        // Header
        if (!empty($this->headers)) {
            $output .= $this->renderRow($this->headers, $this->headerStyle) . "\n";

            if ($this->showBorders) {
                $output .= $this->renderBorder('middle') . "\n";
            }
        }

        // Zeilen
        foreach ($this->rows as $index => $row) {
            $output .= $this->renderRow($row, $this->rowStyle) . "\n";
        }

        if ($this->showBorders) {
            $output .= $this->renderBorder('bottom') . "\n";
        }

        return $output;
    }

    /**
     * Rendert eine Zeile der Tabelle.
     */
    private function renderRow(array $cells, ConsoleStyle $style): string
    {
        $output = '';

        if ($this->showBorders) {
            $output .= $this->borderStyle->apply('│');
        }

        foreach ($cells as $index => $cell) {
            $width = $this->columnWidths[$index] ?? 10;
            $cellText = (string)$cell;

            // Linksbündige Ausrichtung mit exakter Breite
            $paddedCell = str_pad($cellText, $width, ' ', STR_PAD_RIGHT);

            // Padding hinzufügen
            $padding = str_repeat(' ', $this->padding);
            $finalCell = $padding . $paddedCell . $padding;

            $output .= $style->apply($finalCell);

            if ($this->showBorders) {
                $output .= $this->borderStyle->apply('│');
            }
        }

        return $output;
    }

    /**
     * Rendert eine Trennlinie der Tabelle.
     */
    private function renderBorder(string $type): string
    {
        $left = match($type) {
            'top' => '┌',
            'middle' => '├',
            'row' => '├',
            'bottom' => '└',
            default => '│'
        };

        $right = match($type) {
            'top' => '┐',
            'middle' => '┤',
            'row' => '┤',
            'bottom' => '┘',
            default => '│'
        };

        $horizontal = '─';

        $junction = match($type) {
            'top' => '┬',
            'middle' => '┼',
            'row' => '┼',
            'bottom' => '┴',
            default => '│'
        };

        $border = $left;

        foreach ($this->columnWidths as $index => $width) {
            $cellWidth = $width + ($this->padding * 2);
            $border .= str_repeat($horizontal, $cellWidth);

            if ($index < count($this->columnWidths) - 1) {
                $border .= $junction;
            }
        }

        $border .= $right;

        return $this->borderStyle->apply($border);
    }

    /**
     * Berechnet die Breite jeder Spalte basierend auf dem Inhalt.
     */
    private function calculateColumnWidths(): void
    {
        $this->columnWidths = [];

        // Header-Breiten
        foreach ($this->headers as $index => $header) {
            $this->columnWidths[$index] = mb_strlen((string)$header);
        }

        // Zeilen-Breiten
        foreach ($this->rows as $row) {
            foreach ($row as $index => $cell) {
                $length = mb_strlen((string)$cell);
                $this->columnWidths[$index] = max($this->columnWidths[$index] ?? 0, $length);
            }
        }
    }
}
