<?php

namespace PHPNative\Ui\Widget;

use PHPNative\Async\AsyncTask;
use PHPNative\Async\TaskManager;
use PHPNative\Framework\TextRenderer;
use PHPNative\Ui\Component;

class Button extends Container
{
    private Label $label;
    private null|Icon $leadingIcon = null;
    private string $iconPosition = 'left';
    private $onClick = null;
    private $onClickAsync = null;

    public function __construct(
        public string $text = '',
        string $style = '',
        null|callable $onClick = null,
        string $buttonStyle = '',
    ) {
        parent::__construct($style);

        // Texture caching disabled for buttons - causes issues with variable width buttons
        // Text is already cached by TextRenderer, so performance impact is minimal
        // $this->setUseTextureCache(true);

        // Create label inside button
        $this->label = new Label(
            text: $text,
            style: 'text-black ' . $buttonStyle,
        );

        $this->addComponent($this->label);
        $this->onClick = $onClick;
    }

    public function setIcon(null|Icon $icon, string $position = 'left'): void
    {
        $position = strtolower($position);
        if (!in_array($position, ['left', 'right'], true)) {
            throw new \InvalidArgumentException('Button icon position must be "left" or "right".');
        }

        if ($this->leadingIcon !== null) {
            $this->removeChild($this->leadingIcon);
            $this->leadingIcon = null;
        }

        if ($icon !== null) {
            $this->addComponent($icon);
            $this->leadingIcon = $icon;
            $this->iconPosition = $position;

            if ($position === 'left') {
                $this->moveChildBefore($icon, $this->label);
            } else {
                $this->moveChildAfter($icon, $this->label);
            }
        }

        $this->markDirty(true);
    }

    public function setText(string $text): void
    {
        $this->text = $text;
        $this->label->setText($text);
    }

    public function getText(): string
    {
        return $this->text;
    }

    public function setOnClick(callable $onClick): void
    {
        $this->onClick = $onClick;
    }

    public function setStyle(string $style): void
    {
        parent::setStyle($style);
    }

    /**
     * Set async click handler that runs in background thread
     * @param callable $onClickAsync Task to run asynchronously
     * @param callable|null $onComplete Optional callback when task completes
     * @param callable|null $onError Optional callback on error
     */
    public function setOnClickAsync(
        callable $onClickAsync,
        null|callable $onComplete = null,
        null|callable $onError = null,
    ): void {
        $this->onClickAsync = [
            'task' => $onClickAsync,
            'onComplete' => $onComplete,
            'onError' => $onError,
        ];
    }

    public function handleMouseClick(float $mouseX, float $mouseY, int $button): bool
    {
        // Don't handle events if button is not visible
        if (!$this->visible) {
            return false;
        }

        // Debug output
        if (defined('DEBUG_EVENTS') && DEBUG_EVENTS) {
            error_log(sprintf(
                "[Button '%s'] Click at (%.1f, %.1f), bounds: (%.1f, %.1f) to (%.1f, %.1f)",
                $this->text,
                $mouseX,
                $mouseY,
                $this->viewport->x,
                $this->viewport->y,
                $this->viewport->x + $this->viewport->width,
                $this->viewport->y + $this->viewport->height,
            ));
        }

        // Check if click is within button bounds
        if (
            $mouseX >= $this->viewport->x &&
                $mouseX <= ($this->viewport->x + $this->viewport->width) &&
                $mouseY >= $this->viewport->y &&
                $mouseY <= ($this->viewport->y + $this->viewport->height)
        ) {
            // Debug-Hook: Klick auf Button
            if (defined('DEBUG_EVENTS') && DEBUG_EVENTS) {
                error_log(sprintf(
                    '[Button] Click INSIDE "%s" at (%.1f, %.1f)',
                    $this->text,
                    $mouseX,
                    $mouseY,
                ));
            }
            if (defined('DEBUG_EVENTS') && DEBUG_EVENTS) {
                error_log("[Button '{$this->text}'] Click INSIDE button - executing callback");
            }

            // Call async onClick callback if set
            if ($this->onClickAsync !== null) {
                $task = TaskManager::getInstance()->runAsync($this->onClickAsync['task']);

                if ($this->onClickAsync['onComplete'] !== null) {
                    $task->onComplete($this->onClickAsync['onComplete']);
                }

                if ($this->onClickAsync['onError'] !== null) {
                    $task->onError($this->onClickAsync['onError']);
                }
            } elseif ($this->onClick !== null) { // Call sync onClick callback if set
                if (defined('DEBUG_EVENTS') && DEBUG_EVENTS) {
                    error_log(sprintf('[Button] Executing onClick for "%s"', $this->text));
                }
                ($this->onClick)();
            }

            return true;
        }

        if (defined('DEBUG_EVENTS') && DEBUG_EVENTS) {
            error_log("[Button '{$this->text}'] Click OUTSIDE button");
        }

        // Click was outside button - don't handle it
        // Don't call parent::handleMouseClick as that would cause double event propagation
        return false;
    }

    private function removeChild(Component $component): void
    {
        foreach ($this->children as $index => $child) {
            if ($child === $component) {
                if (method_exists($child, 'detachFromWindow')) {
                    $child->detachFromWindow();
                }
                $child->setParent(null);
                unset($this->children[$index]);
            }
        }

        $this->children = array_values($this->children);
    }

    private function moveChildBefore(Component $child, Component $reference): void
    {
        $childIndex = array_search($child, $this->children, true);
        $referenceIndex = array_search($reference, $this->children, true);

        if ($childIndex === false || $referenceIndex === false || $childIndex === $referenceIndex) {
            return;
        }

        array_splice($this->children, $childIndex, 1);
        $referenceIndex = array_search($reference, $this->children, true);
        array_splice($this->children, $referenceIndex, 0, [$child]);
    }

    private function moveChildAfter(Component $child, Component $reference): void
    {
        $childIndex = array_search($child, $this->children, true);
        $referenceIndex = array_search($reference, $this->children, true);

        if ($childIndex === false || $referenceIndex === false || $childIndex === ($referenceIndex + 1)) {
            return;
        }

        array_splice($this->children, $childIndex, 1);
        $referenceIndex = array_search($reference, $this->children, true);
        array_splice($this->children, $referenceIndex + 1, 0, [$child]);
    }
}
