<?php

declare(strict_types=1);

require_once __DIR__ . '/../vendor/autoload.php';

use PHPNative\Framework\Application;
use PHPNative\Ui\Widget\Button;
use PHPNative\Ui\Widget\Container;
use PHPNative\Ui\Widget\Label;
use PHPNative\Ui\Widget\TextInput;
use PHPNative\Ui\Window;

final class KanbanTaskCard extends Container
{
    public function __construct(
        private readonly string $boardId,
        private readonly array $task,
        private KanbanBoardView $boardView,
        bool $selected = false,
    ) {
        $baseStyle = 'bg-white border rounded px-3 py-2 shadow cursor-pointer';
        $style = $selected ? ($baseStyle . ' border-blue-500 bg-blue-50') : ($baseStyle . ' border-gray-200');

        parent::__construct($style);

        $title = new Label($task['title'], 'text-sm text-black');
        $this->addComponent($title);
        if (!empty($task['note'] ?? '')) {
            $this->addComponent(new Label($task['note'], 'text-xs text-gray-500'));
        }
    }

    public function handleMouseClick(float $mouseX, float $mouseY, int $button): bool
    {
        if ($button !== 1) {
            return false;
        }

        // Start drag operation on click
        $this->boardView->beginDrag($this->boardId, $this->task, $this);
        return true;
    }
}

final class KanbanBoardHeader extends Container
{
    public function __construct(
        private readonly string $boardId,
        private KanbanBoardView $boardView,
        string $title,
        int $taskCount,
    ) {
        parent::__construct('flex flex-col gap-1 cursor-pointer');

        $this->addComponent(new Label($title, 'text-lg font-bold text-black'));
        $this->addComponent(new Label(sprintf('%d Aufgaben', $taskCount), 'text-xs text-gray-700'));
        $this->addComponent(new Label('Hierhin verschieben (Klick)', 'text-[10] text-gray-500'));
    }

    public function handleMouseClick(float $mouseX, float $mouseY, int $button): bool
    {
        if ($button !== 1) {
            return false;
        }

        // Nur reagieren, wenn der Klick innerhalb des Header-Viewports liegt
        $vp = $this->getViewport();
        $inside =
            $mouseX >= $vp->x &&
            $mouseX <= ($vp->x + $vp->width) &&
            $mouseY >= $vp->y &&
            $mouseY <= ($vp->y + $vp->height);

        if (!$inside) {
            return false;
        }

        if (defined('DEBUG_EVENTS') && DEBUG_EVENTS) {
            error_log(sprintf('[KanbanHeader] Click on board "%s"', $this->boardId));
        }

        $this->boardView->moveSelectedToBoard($this->boardId);
        return true;
    }
}

final class KanbanBoardView extends Container
{
    private array $boards;
    private array $boardViews = [];
    private null|string $selectedTaskId = null;
    private null|string $selectedBoardId = null;
    private null|array $dragState = null;

    public function __construct(
        private readonly string $storagePath,
        array $initialBoards,
        private readonly Label $statusLabel,
    ) {
        parent::__construct('flex flex-row gap-4 flex-1');
        $this->boards = $initialBoards;

        $this->renderBoards();
    }

    public function addBoard(string $title): void
    {
        $title = trim($title);
        if ($title === '') {
            $this->statusLabel->setText('Board-Namen eingeben, um es hinzuzufügen.');
            return;
        }

        $this->boards[] = [
            'id' => uniqid('board_', true),
            'title' => $title,
            'tasks' => [],
        ];

        $this->saveBoards();
        $this->renderBoards();
        $this->statusLabel->setText('Board hinzugefügt: ' . $title);
    }

    public function addTask(string $boardId, string $title): void
    {
        $title = trim($title);
        if ($title === '') {
            $this->statusLabel->setText('Bitte einen Aufgabentitel eingeben.');
            return;
        }

        foreach ($this->boards as &$board) {
            if ($board['id'] === $boardId) {
                $board['tasks'][] = [
                    'id' => uniqid('task_', true),
                    'title' => $title,
                    'note' => '',
                ];
                $this->saveBoards();
                $this->renderBoards();
                $this->statusLabel->setText(sprintf('Aufgabe "%s" zu "%s" hinzugefügt.', $title, $board['title']));
                return;
            }
        }

        $this->statusLabel->setText('Board nicht gefunden.');
    }

    public function selectTask(string $boardId, array $task): void
    {
        $this->selectedBoardId = $boardId;
        $this->selectedTaskId = $task['id'];
        $msg = sprintf('Ausgewählt: "%s" in "%s"', $task['title'], $this->getBoardTitle($boardId));
        $this->statusLabel->setText($msg);
        if (defined('DEBUG_EVENTS') && DEBUG_EVENTS) {
            error_log('[Kanban] ' . $msg);
        }
        $this->renderBoards();
    }

    public function beginDrag(string $boardId, array $task, KanbanTaskCard $card): void
    {
        $vp = $card->getViewport();

        $ghost = new Container('bg-yellow-300 border-2 border-red-600 rounded px-3 py-2 shadow-2xl');
        $ghost->addComponent(new Label($task['title'], 'text-sm text-black'));
        $ghost->setViewport(clone $vp);
        $ghost->setContentViewport(clone $vp);
        $ghost->setOverlay(true);

        $this->addComponent($ghost);

        $this->dragState = [
            'fromBoardId' => $boardId,
            'task' => $task,
            'ghost' => $ghost,
        ];

        $this->statusLabel->setText('Drag gestartet: ' . $task['title']);
    }

    public function handleDrag(float $mouseX, float $mouseY): void
    {
        if ($this->dragState === null) {
            return;
        }
        /** @var Container $ghost */
        $ghost = $this->dragState['ghost'];
        $vp = $ghost->getViewport();
        $vp->x = (int) ($mouseX - $vp->width / 2);
        $vp->y = (int) ($mouseY - $vp->height / 2);
        $ghost->setViewport($vp);
        $ghost->setContentViewport(clone $vp);
    }

    public function moveSelectedToBoard(string $targetBoardId): void
    {
        if ($this->selectedTaskId === null) {
            if (defined('DEBUG_EVENTS') && DEBUG_EVENTS) {
                error_log('[Kanban] moveSelectedToBoard called without selectedTaskId');
            }
            $this->statusLabel->setText('Keine Aufgabe ausgewählt.');
            return;
        }

        if ($this->selectedBoardId === $targetBoardId) {
            if (defined('DEBUG_EVENTS') && DEBUG_EVENTS) {
                error_log('[Kanban] moveSelectedToBoard target is same board');
            }
            $this->statusLabel->setText('Aufgabe ist bereits in diesem Board.');
            return;
        }

        $movedTask = null;
        foreach ($this->boards as &$board) {
            if ($board['id'] === $this->selectedBoardId) {
                foreach ($board['tasks'] as $index => $task) {
                    if ($task['id'] === $this->selectedTaskId) {
                        $movedTask = $task;
                        array_splice($board['tasks'], $index, 1);
                        break 2;
                    }
                }
            }
        }

        if ($movedTask === null) {
            if (defined('DEBUG_EVENTS') && DEBUG_EVENTS) {
                error_log('[Kanban] moveSelectedToBoard: task not found in source board');
            }
            $this->statusLabel->setText('Ausgewählte Aufgabe konnte nicht gefunden werden.');
            return;
        }

        foreach ($this->boards as &$board) {
            if ($board['id'] === $targetBoardId) {
                $board['tasks'][] = $movedTask;
                break;
            }
        }

        // Nach erfolgreichem Verschieben Auswahl zurücksetzen,
        // damit weitere Board-Klicks den Task nicht erneut verschieben.
        $this->selectedBoardId = null;
        $this->selectedTaskId = null;

        $this->saveBoards();
        $this->renderBoards();
        $msg = sprintf('"%s" nach "%s" verschoben.', $movedTask['title'], $this->getBoardTitle($targetBoardId));
        $this->statusLabel->setText($msg);
        if (defined('DEBUG_EVENTS') && DEBUG_EVENTS) {
            error_log('[Kanban] ' . $msg);
        }
    }

    public function handleMouseRelease(float $mouseX, float $mouseY, int $button): void
    {
        parent::handleMouseRelease($mouseX, $mouseY, $button);

        if ($button !== 1 || $this->dragState === null) {
            return;
        }

        // Determine drop target board
        $targetBoardId = null;
        foreach ($this->boardViews as $boardId => $info) {
            $vp = $info['column']->getViewport();
            if (
                $mouseX >= $vp->x &&
                $mouseX <= ($vp->x + $vp->width) &&
                $mouseY >= $vp->y &&
                $mouseY <= ($vp->y + $vp->height)
            ) {
                $targetBoardId = $boardId;
                break;
            }
        }

        // Remove ghost
        if (($this->dragState['ghost'] ?? null) instanceof Container) {
            $this->dragState['ghost']->setVisible(false);
        }

        $state = $this->dragState;
        $this->dragState = null;

        if ($targetBoardId !== null) {
            $this->selectedBoardId = $state['fromBoardId'];
            $this->selectedTaskId = $state['task']['id'];
            $this->moveSelectedToBoard($targetBoardId);
        } else {
            $this->statusLabel->setText('Drag abgebrochen.');
        }
    }

    private function renderBoards(): void
    {
        $this->clearChildren();
        $this->boardViews = [];

        foreach ($this->boards as $board) {
            $defaultStyle = 'flex flex-col w-[340] flex-none bg-white border border-gray-300 rounded-2xl p-5 gap-3';
            $highlightStyle = 'flex flex-col w-[340] flex-none bg-blue-50 border-2 border-blue-500 rounded-2xl p-5 gap-3';

            $column = new Container($defaultStyle);

            // Header mit Titel und Task-Anzahl, klickbar als Drop-Ziel
            $header = new KanbanBoardHeader($board['id'], $this, $board['title'], count($board['tasks']));
            $column->addComponent($header);

            // Task-Karten (Buttons) mit Auswahl-Hervorhebung
            if (!empty($board['tasks'])) {
                $taskList = new Container('flex flex-col gap-3 mt-3');
                foreach ($board['tasks'] as $task) {
                    $isSelected = $this->selectedTaskId === $task['id'];
                    $style = $isSelected
                        ? 'w-full text-left bg-blue-50 border border-blue-500 rounded-lg px-4 py-3 shadow-md cursor-pointer'
                        : 'w-full text-left bg-white border border-gray-200 rounded-lg px-4 py-3 shadow-md cursor-pointer';

                    $button = new Button($task['title'], $style);
                    $button->setOnClick(function () use ($board, $task): void {
                        // Debug-Ausgabe in Statuszeile, um Klicks sicher zu sehen
                        $this->statusLabel->setText(sprintf(
                            'Task-Klick: "%s" in "%s"',
                            $task['title'],
                            $this->getBoardTitle($board['id']),
                        ));
                        $this->selectTask($board['id'], $task);
                    });

                    $taskList->addComponent($button);
                }
                $column->addComponent($taskList);
            }

            $this->addComponent($column);
            $this->boardViews[$board['id']] = [
                'column' => $column,
                'defaultStyle' => $defaultStyle,
                'highlightStyle' => $highlightStyle,
            ];
        }
    }

    private function getBoardTitle(string $boardId): string
    {
        foreach ($this->boards as $board) {
            if ($board['id'] === $boardId) {
                return $board['title'];
            }
        }

        return $boardId;
    }

    private function saveBoards(): void
    {
        file_put_contents(
            $this->storagePath,
            json_encode($this->boards, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE),
            LOCK_EX,
        );
    }
}

$storagePath = __DIR__ . '/kanban_data.json';

$boards = [];
if (is_file($storagePath)) {
    $raw = file_get_contents($storagePath);
    $decoded = json_decode($raw ?: '[]', true);
    if (is_array($decoded)) {
        $boards = $decoded;
    }
}

if (empty($boards)) {
    $boards = [
        [
            'id' => uniqid('board_', true),
            'title' => 'Backlog',
            'tasks' => [
                ['id' => uniqid('task_', true), 'title' => 'Idee sammeln', 'note' => ''],
                ['id' => uniqid('task_', true), 'title' => 'Mockups skizzieren', 'note' => ''],
            ],
        ],
        [
            'id' => uniqid('board_', true),
            'title' => 'In Arbeit',
            'tasks' => [
                ['id' => uniqid('task_', true), 'title' => 'API anbinden', 'note' => ''],
            ],
        ],
        [
            'id' => uniqid('board_', true),
            'title' => 'Erledigt',
            'tasks' => [
                ['id' => uniqid('task_', true), 'title' => 'UI Grundlayout', 'note' => ''],
            ],
        ],
    ];
    file_put_contents($storagePath, json_encode($boards, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), LOCK_EX);
}
define('DEBUG_EVENTS', false);
$app = new Application();
$window = new Window('Kanban Beispiel', 1200, 800);

$root = new Container('flex flex-col h-full w-full bg-gray-100 gap-6 p-6');

$title = new Label('Kanban Board', 'text-3xl font-bold text-black');
$subTitle = new Label(
    'Boards hinzufügen, Aufgaben erstellen und per Drag & Drop verschieben.',
    'text-base text-gray-700',
);
$root->addComponent($title);
$root->addComponent($subTitle);

$statusLabel = new Label('Bereit.', 'text-sm text-gray-600');
$kanbanView = new KanbanBoardView($storagePath, $boards, $statusLabel);

// SDL_Window PixelDensity und DisplayScale im Status anzeigen (falls verfügbar)
$densityText = '';
if (function_exists('sdl_get_window_pixel_density')) {
    $density = sdl_get_window_pixel_density($window->getWindowResource());
    $densityText .= sprintf('PixelDensity: %.2f', $density);
}
if (function_exists('sdl_get_window_display_scale')) {
    $scale = sdl_get_window_display_scale($window->getWindowResource());
    $densityText .= ($densityText !== '' ? ' | ' : '') . sprintf('DisplayScale: %.2f', $scale);
}
if (function_exists('sdl_get_display_content_scale')) {
    $contentScale = sdl_get_display_content_scale($window->getWindowResource());
    $densityText .= ($densityText !== '' ? ' | ' : '') . sprintf('ContentScale: %.2f', $contentScale);
}
// Fallback: effektiven Scale aus WindowSize vs. WindowSizeInPixels berechnen
if (function_exists('sdl_get_window_size') && function_exists('sdl_get_window_size_in_pixels')) {
    $logical = sdl_get_window_size($window->getWindowResource());
    $pixels = sdl_get_window_size_in_pixels($window->getWindowResource());
    if (is_array($logical) && is_array($pixels) && $logical[0] > 0 && $logical[1] > 0) {
        $scaleX = $pixels[0] / $logical[0];
        $scaleY = $pixels[1] / $logical[1];
        $densityText .= ($densityText !== '' ? ' | ' : '') . sprintf('EffectiveScale: %.2f x %.2f', $scaleX, $scaleY);
    }
}
if (function_exists('sdl_get_current_video_driver')) {
    $driver = sdl_get_current_video_driver();
    if ($driver !== false) {
        $densityText .= ($densityText !== '' ? ' | ' : '') . 'VideoDriver: ' . $driver;
    }
}
if ($densityText !== '') {
    $statusLabel->setText('Bereit. ' . $densityText);
}

$boardInput = new TextInput('Neues Board', 'flex-1 border border-gray-300 rounded px-3 py-2 bg-white text-black');
$boardAddButton = new Button('Board hinzufügen', 'px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700');
$boardAddButton->setOnClick(function () use ($kanbanView, $boardInput, $statusLabel): void {
    $kanbanView->addBoard($boardInput->getValue());
    $boardInput->setValue('');
});
$boardRow = new Container('flex flex-row gap-3 items-center');
$boardRow->addComponent($boardInput);
$boardRow->addComponent($boardAddButton);
$root->addComponent($boardRow);

$root->addComponent($kanbanView);
$root->addComponent($statusLabel);

$window->setRoot($root);
$app->addWindow($window);
$app->run();
