<?php

declare(strict_types=1);

namespace App\Framework\Console\Components;

use App\Framework\Console\CommandHistory;
use App\Framework\Console\HistoryTab;
use App\Framework\Console\TuiKeyCode;
use App\Framework\Console\TuiView;
use App\Framework\Discovery\ValueObjects\DiscoveredAttribute;

/**
 * Handles all keyboard input and navigation for the TUI
 */
final readonly class TuiInputHandler
{
    public function __construct(
        private TuiCommandExecutor $commandExecutor
    ) {
    }

    /**
     * Handle keyboard input based on current view
     */
    public function handleInput(string $key, TuiState $state, CommandHistory $history): void
    {
        // Global shortcuts first
        if ($this->handleGlobalShortcuts($key, $state)) {
            return;
        }

        // View-specific handling
        match ($state->getCurrentView()) {
            TuiView::CATEGORIES => $this->handleCategoriesInput($key, $state),
            TuiView::COMMANDS => $this->handleCommandsInput($key, $state),
            TuiView::SEARCH => $this->handleSearchInput($key, $state),
            TuiView::HISTORY => $this->handleHistoryInput($key, $state, $history),
            TuiView::FORM => $this->handleFormInput($key, $state),
            TuiView::DASHBOARD => $this->handleDashboardInput($key, $state),
            TuiView::HELP => $this->handleHelpInput($key, $state),
        };
    }

    /**
     * Handle global shortcuts available in all views
     */
    private function handleGlobalShortcuts(string $key, TuiState $state): bool
    {
        switch ($key) {
            case 'q':
            case 'Q':
            case TuiKeyCode::ESCAPE->value:
                $state->setRunning(false);

                return true;

            case 'd':
            case 'D':
                $state->setCurrentView(TuiView::DASHBOARD);

                return true;

            case 'h':
            case 'H':
                $state->setCurrentView(TuiView::HELP);

                return true;

            case '/':
            case 's':
            case 'S':
                $state->setCurrentView(TuiView::SEARCH);
                $state->resetSearchState();

                return true;

            case 'r':
            case 'R':
                $state->setCurrentView(TuiView::HISTORY);
                $state->setSelectedHistoryItem(0);

                return true;

            case TuiKeyCode::F1->value:
                $this->commandExecutor->showAllCommandsHelp();

                return true;

            case 'c':
            case 'C':
                if ($state->getCurrentView() !== TuiView::CATEGORIES) {
                    $state->setCurrentView(TuiView::CATEGORIES);

                    return true;
                }

                break;
        }

        return false;
    }

    /**
     * Handle input in categories view
     */
    private function handleCategoriesInput(string $key, TuiState $state): void
    {
        switch ($key) {
            case TuiKeyCode::ARROW_UP->value:
                $state->navigateUp();

                break;

            case TuiKeyCode::ARROW_DOWN->value:
                $state->navigateDown();

                break;

            case TuiKeyCode::ENTER->value:
                $state->setCurrentView(TuiView::COMMANDS);
                $state->setSelectedCommand(0);

                break;
        }
    }

    /**
     * Handle input in commands view
     */
    private function handleCommandsInput(string $key, TuiState $state): void
    {
        switch ($key) {
            case TuiKeyCode::ARROW_UP->value:
                $state->navigateUp();

                break;

            case TuiKeyCode::ARROW_DOWN->value:
                $state->navigateDown();

                break;

            case TuiKeyCode::ENTER->value:
                $command = $state->getCurrentCommand();
                if ($command) {
                    $this->commandExecutor->executeSelectedCommand($command);
                }

                break;

            case TuiKeyCode::SPACE->value:
                $command = $state->getCurrentCommand();
                if ($command) {
                    $state->setSelectedCommandForForm($command);
                    $state->setCurrentView(TuiView::FORM);
                }

                break;

            case 'v':
            case 'V':
                $command = $state->getCurrentCommand();
                if ($command) {
                    $this->commandExecutor->validateSelectedCommand($command);
                }

                break;

            case 'h':
            case 'H':
                $command = $state->getCurrentCommand();
                if ($command) {
                    $this->commandExecutor->showSelectedCommandHelp($command);
                }

                break;

            case TuiKeyCode::ARROW_LEFT->value:
            case TuiKeyCode::BACKSPACE->value:
                $state->setCurrentView(TuiView::CATEGORIES);

                break;
        }
    }

    /**
     * Handle input in search view
     */
    private function handleSearchInput(string $key, TuiState $state): void
    {
        switch ($key) {
            case TuiKeyCode::ESCAPE->value:
                $state->setCurrentView(TuiView::CATEGORIES);
                $state->resetSearchState();

                break;

            case TuiKeyCode::ENTER->value:
                $command = $state->getCurrentSearchResult();
                if ($command) {
                    // Handle DiscoveredAttribute objects
                    if ($command instanceof DiscoveredAttribute) {
                        $attribute = $command->createAttributeInstance();
                        if ($attribute !== null) {
                            $this->commandExecutor->executeCommand($attribute->name);
                        }
                    } else {
                        $this->commandExecutor->executeCommand($command->name);
                    }
                }

                break;

            case TuiKeyCode::SPACE->value:
                $command = $state->getCurrentSearchResult();
                if ($command) {
                    $state->setSelectedCommandForForm($command);
                    $state->setCurrentView(TuiView::FORM);
                }

                break;

            case 'h':
            case 'H':
                $command = $state->getCurrentSearchResult();
                if ($command) {
                    // Handle DiscoveredAttribute objects
                    if ($command instanceof DiscoveredAttribute) {
                        $attribute = $command->createAttributeInstance();
                        if ($attribute !== null) {
                            $this->commandExecutor->showCommandHelp($attribute->name);
                        }
                    } else {
                        $this->commandExecutor->showCommandHelp($command->name);
                    }
                }

                break;

            case 'v':
            case 'V':
                $command = $state->getCurrentSearchResult();
                if ($command) {
                    // Handle DiscoveredAttribute objects
                    if ($command instanceof DiscoveredAttribute) {
                        $attribute = $command->createAttributeInstance();
                        if ($attribute !== null) {
                            $this->commandExecutor->validateCommand($attribute->name);
                        }
                    } else {
                        $this->commandExecutor->validateCommand($command->name);
                    }
                }

                break;

            case TuiKeyCode::ARROW_UP->value:
                $state->navigateUp();

                break;

            case TuiKeyCode::ARROW_DOWN->value:
                $state->navigateDown();

                break;

            case TuiKeyCode::BACKSPACE->value:
            case "\x7f": // DEL key
                $query = $state->getSearchQuery();
                if (strlen($query) > 0) {
                    $newQuery = substr($query, 0, -1);
                    $state->setSearchQuery($newQuery);
                    $this->updateSearchResults($state);
                }

                break;

            default:
                // Add character to search query
                if (strlen($key) === 1 && ctype_print($key)) {
                    $newQuery = $state->getSearchQuery() . $key;
                    $state->setSearchQuery($newQuery);
                    $this->updateSearchResults($state);
                }

                break;
        }
    }

    /**
     * Handle input in history view
     */
    private function handleHistoryInput(string $key, TuiState $state, CommandHistory $history): void
    {
        switch ($key) {
            case TuiKeyCode::ARROW_UP->value:
                $state->navigateUp();

                break;

            case TuiKeyCode::ARROW_DOWN->value:
                $state->navigateDown();

                break;

            case TuiKeyCode::ARROW_LEFT->value:
                $this->switchHistoryTab($state, -1);

                break;

            case TuiKeyCode::ARROW_RIGHT->value:
                $this->switchHistoryTab($state, 1);

                break;

            case TuiKeyCode::ENTER->value:
                $items = $this->getHistoryItems($state, $history);
                if (! empty($items) && isset($items[$state->getSelectedHistoryItem()])) {
                    $command = $items[$state->getSelectedHistoryItem()]['command'];
                    $history->addToHistory($command);
                    $this->commandExecutor->executeCommand($command);
                }

                break;

            case TuiKeyCode::SPACE->value:
                $items = $this->getHistoryItems($state, $history);
                if (! empty($items) && isset($items[$state->getSelectedHistoryItem()])) {
                    $commandName = $items[$state->getSelectedHistoryItem()]['command'];
                    $commandObject = $this->commandExecutor->findCommandObject($commandName);
                    if ($commandObject) {
                        $state->setSelectedCommandForForm($commandObject);
                        $state->setCurrentView(TuiView::FORM);
                    }
                }

                break;

            case 'h':
            case 'H':
                $items = $this->getHistoryItems($state, $history);
                if (! empty($items) && isset($items[$state->getSelectedHistoryItem()])) {
                    $commandName = $items[$state->getSelectedHistoryItem()]['command'];
                    $this->commandExecutor->showCommandHelp($commandName);
                }

                break;

            case 'v':
            case 'V':
                $items = $this->getHistoryItems($state, $history);
                if (! empty($items) && isset($items[$state->getSelectedHistoryItem()])) {
                    $commandName = $items[$state->getSelectedHistoryItem()]['command'];
                    $this->commandExecutor->validateCommand($commandName);
                }

                break;

            case 'f':
            case 'F':
                $items = $this->getHistoryItems($state, $history);
                if (! empty($items) && isset($items[$state->getSelectedHistoryItem()])) {
                    $command = $items[$state->getSelectedHistoryItem()]['command'];
                    $history->toggleFavorite($command);
                }

                break;

            case 'c':
            case 'C':
                if ($state->getHistoryTab() === HistoryTab::FAVORITES) {
                    $history->clearFavorites();
                } else {
                    $history->clearHistory();
                }

                break;

            case TuiKeyCode::ESCAPE->value:
            case TuiKeyCode::BACKSPACE->value:
                $state->setCurrentView(TuiView::CATEGORIES);

                break;
        }
    }

    /**
     * Handle input in form view
     */
    private function handleFormInput(string $key, TuiState $state): void
    {
        switch ($key) {
            case TuiKeyCode::ESCAPE->value:
                $state->resetFormState();
                $state->setCurrentView(TuiView::CATEGORIES);

                break;
        }
    }

    /**
     * Handle input in dashboard view
     */
    private function handleDashboardInput(string $key, TuiState $state): void
    {
        switch ($key) {
            case TuiKeyCode::ESCAPE->value:
                $state->setCurrentView(TuiView::CATEGORIES);

                break;
        }
    }

    /**
     * Handle input in help view
     */
    private function handleHelpInput(string $key, TuiState $state): void
    {
        switch ($key) {
            case TuiKeyCode::ESCAPE->value:
                $state->setCurrentView(TuiView::CATEGORIES);

                break;
        }
    }

    /**
     * Update search results based on current query
     */
    private function updateSearchResults(TuiState $state): void
    {
        $query = strtolower($state->getSearchQuery());

        if (empty($query)) {
            $state->setSearchResults([]);

            return;
        }

        $results = [];
        $categories = $state->getCategories();

        foreach ($categories as $category) {
            foreach ($category['commands'] as $command) {
                // Handle DiscoveredAttribute objects
                if ($command instanceof DiscoveredAttribute) {
                    $attribute = $command->createAttributeInstance();
                    if ($attribute === null) {
                        continue;
                    }
                    $commandName = strtolower($attribute->name);
                    $commandDescription = strtolower($attribute->description ?? '');
                } else {
                    // Fallback for legacy objects
                    $commandName = strtolower($command->name ?? '');
                    $commandDescription = strtolower($command->description ?? '');
                }

                if (str_contains($commandName, $query) || str_contains($commandDescription, $query)) {
                    $results[] = $command;
                }
            }
        }

        $state->setSearchResults($results);
    }

    /**
     * Switch between history tabs
     */
    private function switchHistoryTab(TuiState $state, int $direction): void
    {
        $tabs = [HistoryTab::RECENT, HistoryTab::FREQUENT, HistoryTab::FAVORITES];
        $currentIndex = array_search($state->getHistoryTab(), $tabs);

        $newIndex = ($currentIndex + $direction + count($tabs)) % count($tabs);
        $state->setHistoryTab($tabs[$newIndex]);
    }

    /**
     * Get history items based on current tab
     */
    private function getHistoryItems(TuiState $state, CommandHistory $history): array
    {
        return match ($state->getHistoryTab()) {
            HistoryTab::RECENT => $history->getRecentHistory(10),
            HistoryTab::FREQUENT => $history->getFrequentCommands(10),
            HistoryTab::FAVORITES => $history->getFavorites(),
        };
    }
}
