<?php

namespace PHPNative\Ui\Widget;

use PHPNative\Framework\TextRenderer;
use PHPNative\Tailwind\Style\Background;
use PHPNative\Ui\Component;
use PHPNative\Ui\Viewport;

class Modal extends Container
{
    private Container $content;
    private int $backdropAlpha;

    public function __construct(
        Container $content,
        string $style = 'flex items-center justify-center bg-black',
        int $backdropAlpha = 160,
    ) {
        parent::__construct(trim($style));

        $this->content = $content;
        $this->backdropAlpha = max(0, min(255, $backdropAlpha));

        $this->setOverlay(true);
        $this->setVisible(false);
        $this->setZIndex(1000);
        $this->setUseTextureCache(false);

        $this->addComponent($content);
    }

    public function layout(null|TextRenderer $textRenderer = null): void
    {
        $windowViewport = $this->attachedWindow?->getViewport();
        if ($windowViewport instanceof Viewport) {
            $referenceViewport = $windowViewport;
        } else {
            $referenceViewport = $this->getParent()?->getViewport() ?? $this->getViewport();
        }
        $overlayViewport = new Viewport(
            x: 0,
            y: 0,
            width: $referenceViewport->windowWidth,
            height: $referenceViewport->windowHeight,
            windowWidth: $referenceViewport->windowWidth,
            windowHeight: $referenceViewport->windowHeight,
        );

        // Set viewport for the modal background (full window)
        $this->setViewport($overlayViewport);
        $this->setContentViewport(clone $overlayViewport);

        // Parse styles for the modal background
        $styleCollection = \PHPNative\Tailwind\StyleParser::parse($this->style);
        $this->computedStyles = $styleCollection->getValidStyles(
            \PHPNative\Tailwind\Style\MediaQueryEnum::normal,
            \PHPNative\Tailwind\Style\StateEnum::normal,
        );

        if (isset($this->computedStyles[Background::class])) {
            $this->computedStyles[Background::class]->color->alpha = $this->backdropAlpha;
        }

        // Calculate max size for content (with padding)
        $windowWidth = $overlayViewport->width;
        $windowHeight = $overlayViewport->height;
        $maxWidth = max(240, $windowWidth - 80);
        $maxHeight = max(160, $windowHeight - 80);

        // Measure content with max constraints
        $measurementViewport = new Viewport(
            x: 0,
            y: 0,
            width: $maxWidth,
            height: $maxHeight,
            windowWidth: $windowWidth,
            windowHeight: $windowHeight,
        );

        $this->content->setViewport($measurementViewport);
        $this->content->setContentViewport(clone $measurementViewport);
        $this->content->layout($textRenderer);

        // Get measured size
        $measuredBounds = $this->content->getViewport();
        $contentWidth = min($measuredBounds->width, $maxWidth);
        $contentHeight = min($measuredBounds->height, $maxHeight);

        // Center the content
        $targetX = (int) max(0, ($windowWidth - $contentWidth) / 2);
        $targetY = (int) max(0, ($windowHeight - $contentHeight) / 2);

        // Apply final viewport to content
        $finalViewport = new Viewport(
            x: $targetX,
            y: $targetY,
            width: $contentWidth,
            height: $contentHeight,
            windowWidth: $windowWidth,
            windowHeight: $windowHeight,
        );

        $this->content->setViewport($finalViewport);
        $this->content->setContentViewport(clone $finalViewport);
        $this->content->layout($textRenderer);
    }

    /**
     * Allow replacing the content container.
     */
    public function setContent(Container $content): void
    {
        $this->removeChild($this->content);
        $this->content = $content;
        $this->addComponent($content);
        $this->markDirty(true);
    }

    /**
     * Expose the content container for further customization.
     */
    public function getContent(): Container
    {
        return $this->content;
    }

    public function setBackdropAlpha(int $alpha): void
    {
        $this->backdropAlpha = max(0, min(255, $alpha));
        $this->markDirty(false);
    }

    public function setVisible(bool $visible): void
    {
        $wasVisible = $this->isVisible();
        parent::setVisible($visible);

        // When modal becomes visible, clear hover states on background components
        if ($visible && !$wasVisible && $this->attachedWindow) {
            // Send a mouse move event outside the window to clear all hover states
            $rootComponent = $this->attachedWindow->getRoot();
            if ($rootComponent) {
                $rootComponent->handleMouseMove(-1000, -1000);
            }
        }
    }

    public function handleMouseClick(float $mouseX, float $mouseY, int $button): bool
    {
        if (!$this->isVisible()) {
            return false;
        }

        parent::handleMouseClick($mouseX, $mouseY, $button);
        return true;
    }

    public function handleMouseMove(float $mouseX, float $mouseY): void
    {
        if (!$this->isVisible()) {
            return;
        }

        // Pass mouse move to children but don't mark the modal itself as dirty
        foreach ($this->children as $child) {
            $child->handleMouseMove($mouseX, $mouseY);
        }

        // Don't propagate to components below the modal
    }

    public function handleMouseWheel(float $mouseX, float $mouseY, float $deltaY): bool
    {
        if (!$this->isVisible()) {
            return false;
        }

        parent::handleMouseWheel($mouseX, $mouseY, $deltaY);
        return true;
    }

    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);
    }
}
