<?php

declare(strict_types=1);

namespace App\Framework\Console\Components;

use App\Framework\Console\ConsoleColor;
use App\Framework\Console\ConsoleOutput;
use App\Framework\Console\ConsoleOutputInterface;

/**
 * Klasse für interaktive Menüs in der Konsole.
 * Unterstützt sowohl einfache nummerierte Menüs als auch
 * Menüs mit Pfeiltasten-Navigation.
 */
final class InteractiveMenu
{
    private ConsoleOutput $output;

    private array $menuItems = [];

    private string $title = '';

    private int $selectedIndex = 0;

    private bool $showNumbers = true;

    public function __construct(ConsoleOutputInterface $output)
    {
        $this->output = $output;
    }

    /**
     * Setzt den Titel des Menüs.
     */
    public function setTitle(string $title): self
    {
        $this->title = $title;

        return $this;
    }

    /**
     * Fügt einen Menüpunkt hinzu.
     *
     * @param string $label Die Beschriftung des Menüpunkts
     * @param callable|null $action Eine optionale Aktion, die bei Auswahl ausgeführt wird
     * @param mixed $value Ein optionaler Wert, der zurückgegeben wird
     */
    public function addItem(string $label, ?callable $action = null, mixed $value = null): self
    {
        $this->menuItems[] = [
            'label' => $label,
            'action' => $action,
            'value' => $value ?? $label,
        ];

        return $this;
    }

    /**
     * Fügt einen Separator zum Menü hinzu.
     */
    public function addSeparator(): self
    {
        $this->menuItems[] = [
            'label' => '---',
            'action' => null,
            'value' => null,
            'separator' => true,
        ];

        return $this;
    }

    /**
     * Steuert, ob Nummern angezeigt werden sollen.
     */
    public function showNumbers(bool $show = true): self
    {
        $this->showNumbers = $show;

        return $this;
    }

    /**
     * Zeigt ein einfaches Menü mit Nummern-Auswahl.
     */
    public function showSimple(): mixed
    {
        // Verwende den ScreenManager anstelle des direkten clearScreen()
        $this->output->screen->newMenu();

        if ($this->title) {
            $this->output->writeLine($this->title, ConsoleColor::BRIGHT_CYAN);
            $this->output->writeLine(str_repeat('=', strlen($this->title)));
            $this->output->writeLine('');
        }

        foreach ($this->menuItems as $index => $item) {
            if (isset($item['separator'])) {
                $this->output->writeLine($item['label'], ConsoleColor::GRAY);

                continue;
            }

            $number = $this->showNumbers ? ($index + 1) . '. ' : '';
            $this->output->writeLine($number . $item['label']);
        }

        $this->output->writeLine('');
        $this->output->write('Ihre Wahl: ', ConsoleColor::BRIGHT_CYAN);

        $input = trim(fgets(STDIN));

        if (is_numeric($input)) {
            $selectedIndex = (int)$input - 1;
            if (isset($this->menuItems[$selectedIndex]) && ! isset($this->menuItems[$selectedIndex]['separator'])) {
                $item = $this->menuItems[$selectedIndex];

                if ($item['action']) {
                    return $item['action']();
                }

                return $item['value'];
            }
        }

        $this->output->writeError('Ungültige Auswahl!');

        return $this->showSimple();
    }

    /**
     * Zeigt ein interaktives Menü mit Pfeiltasten-Navigation.
     */
    public function showInteractive(): mixed
    {
        $this->output->screen->setInteractiveMode();

        // Terminal in Raw-Modus setzen für Tastatur-Input
        $this->setRawMode(true);

        try {
            while (true) {
                $this->renderMenu();
                $key = $this->readKey();

                switch ($key) {
                    case "\033[A": // Pfeil hoch
                        $this->moveUp();

                        break;
                    case "\033[B": // Pfeil runter
                        $this->moveDown();

                        break;
                    case "\n": // Enter
                    case "\r":
                        return $this->selectCurrentItem();
                    case "\033": // ESC
                        return null;
                    case 'q':
                    case 'Q':
                        return null;
                }
            }
        } finally {
            $this->setRawMode(false);
        }
    }

    /**
     * Rendert das Menü auf dem Bildschirm.
     */
    private function renderMenu(): void
    {
        // Verwende den ScreenManager anstelle des direkten clearScreen()
        $this->output->screen->newMenu();

        if ($this->title) {
            $this->output->writeLine($this->title, ConsoleColor::BRIGHT_CYAN);
            $this->output->writeLine(str_repeat('=', strlen($this->title)));
            $this->output->writeLine('');
        }

        foreach ($this->menuItems as $index => $item) {
            if (isset($item['separator'])) {
                $this->output->writeLine($item['label'], ConsoleColor::GRAY);

                continue;
            }

            $isSelected = ($index === $this->selectedIndex);
            $prefix = $isSelected ? '► ' : '  ';
            $color = $isSelected ? ConsoleColor::BRIGHT_YELLOW : null;

            $number = $this->showNumbers ? ($index + 1) . '. ' : '';
            $this->output->writeLine($prefix . $number . $item['label'], $color);
        }

        $this->output->writeLine('');
        $this->output->writeLine('Verwenden Sie ↑/↓ zum Navigieren, Enter zum Auswählen, ESC/Q zum Beenden', ConsoleColor::GRAY);
    }

    /**
     * Bewegt die Auswahl nach oben.
     */
    private function moveUp(): void
    {
        do {
            $this->selectedIndex = ($this->selectedIndex - 1 + count($this->menuItems)) % count($this->menuItems);
        } while (isset($this->menuItems[$this->selectedIndex]['separator']) && count($this->menuItems) > 1);
    }

    /**
     * Bewegt die Auswahl nach unten.
     */
    private function moveDown(): void
    {
        do {
            $this->selectedIndex = ($this->selectedIndex + 1) % count($this->menuItems);
        } while (isset($this->menuItems[$this->selectedIndex]['separator']) && count($this->menuItems) > 1);
    }

    /**
     * Wählt den aktuellen Menüpunkt aus.
     */
    private function selectCurrentItem(): mixed
    {
        $item = $this->menuItems[$this->selectedIndex];

        if ($item['action']) {
            return $item['action']();
        }

        return $item['value'];
    }

    /**
     * Liest einen Tastendruck.
     */
    private function readKey(): string
    {
        $key = fgetc(STDIN);

        // Handle Docker/non-interactive environment
        if ($key === false) {
            return 'q'; // Auto-quit in non-interactive mode
        }

        // Behandle Escape-Sequenzen
        if ($key === "\033") {
            $key .= fgetc(STDIN);
            if ($key === "\033[") {
                $key .= fgetc(STDIN);
            }
        }

        return $key;
    }

    /**
     * Setzt den Terminal-Modus.
     */
    private function setRawMode(bool $enable): void
    {
        if ($enable) {
            system('stty -echo -icanon min 1 time 0');
        } else {
            system('stty echo icanon');
        }
    }

    // Die clearScreen-Methode wurde entfernt, da sie durch den ScreenManager ersetzt wurde.
    // Verwende stattdessen $this->output->screen()->newScreen() oder $this->output->display()->clear().
}
