<?php

namespace PHPNative\Ui\Widget;

use PHPNative\Framework\IconFontRegistry;
use PHPNative\Tailwind\Style\Padding;
use PHPNative\Tailwind\Style\Text;
use PHPNative\Ui\Component;

class Icon extends Component
{
    private string $glyph;
    private int $size;
    private null|string $fontPath;
    private mixed $texture = null;
    private int $textureWidth = 0;
    private int $textureHeight = 0;

    public function __construct(
        string|int|\PHPNative\Tailwind\Data\Icon $icon,
        int $size = 16,
        string $style = '',
        null|string $fontPath = null,
    ) {
        parent::__construct($style);

        $this->glyph = $this->resolveGlyph($icon);
        $this->size = max(1, $size);
        $this->fontPath = $fontPath;
    }

    public function setIcon(string|int|\PHPNative\Tailwind\Data\Icon $icon): void
    {
        $glyph = $this->resolveGlyph($icon);
        if ($glyph === $this->glyph) {
            return;
        }

        $this->glyph = $glyph;
        $this->clearTexture();
        $this->markDirty(true);
    }

    public function setSize(int $size): void
    {
        $size = max(1, $size);
        if ($this->size === $size) {
            return;
        }

        $this->size = $size;
        $this->clearTexture();
        $this->markDirty(true);
    }

    public function setFontPath(null|string $fontPath): void
    {
        if ($this->fontPath === $fontPath) {
            return;
        }

        $this->fontPath = $fontPath;
        $this->clearTexture();
        $this->markDirty(true);
    }

    public function layout(null|\PHPNative\Framework\TextRenderer $textRenderer = null): void
    {
        parent::layout($textRenderer);

        $font = IconFontRegistry::getFont($this->size, $this->fontPath);
        $width = $this->size;
        $height = $this->size;

        if ($font) {
            $dimensions = ttf_size_text($font, $this->glyph);
            if ($dimensions !== false) {
                $width = ((int) $dimensions['w']) * $this->viewport->uiScale;
                $height = ((int) $dimensions['h']) * $this->viewport->uiScale;
            }
        }

        if (!isset($this->computedStyles[\PHPNative\Tailwind\Style\Width::class])) {
            $this->viewport->width = $width;
            $this->contentViewport->width = $width;
        }

        if (!isset($this->computedStyles[\PHPNative\Tailwind\Style\Height::class])) {
            $this->viewport->height = $height;
            $this->contentViewport->height = $height;
        }

        if (isset($this->computedStyles[Padding::class]) && ($padding = $this->computedStyles[Padding::class])) {
            $this->viewport->width = $width + $padding->left + $padding->right;
            $this->viewport->height = $height + $padding->top + $padding->bottom;
            $this->contentViewport->width = $width;
            $this->contentViewport->height = $height;
        }
    }

    public function renderContent(&$renderer, null|\PHPNative\Framework\TextRenderer $textRenderer = null): void
    {
        if (!$this->isVisible()) {
            return;
        }

        if ($this->texture === null || $this->isDirty()) {
            $this->createTexture($renderer);
        }

        if ($this->texture !== null) {
            sdl_render_texture($renderer, $this->texture, [
                'x' => (int) $this->contentViewport->x,
                'y' => (int) $this->contentViewport->y,
                'w' => $this->textureWidth,
                'h' => $this->textureHeight,
            ]);
        }

        parent::renderContent($renderer, $textRenderer);
    }

    public function __destruct()
    {
        $this->clearTexture();
        parent::__destruct();
    }

    private function createTexture($renderer): void
    {
        $this->clearTexture();

        $font = IconFontRegistry::getFont($this->size * $this->viewport->uiScale, $this->fontPath);
        if (!$font) {
            $this->renderDirty = false;
            return;
        }

        $textStyle = $this->computedStyles[Text::class] ?? new Text();
        $color = $textStyle->color;
        $r = max(0, min(255, $color->red >= 0 ? $color->red : 0));
        $g = max(0, min(255, $color->green >= 0 ? $color->green : 0));
        $b = max(0, min(255, $color->blue >= 0 ? $color->blue : 0));
        $a = max(0, min(255, $color->alpha));

        $surface = ttf_render_text_blended($font, $this->glyph, $r, $g, $b);
        if (!$surface) {
            $this->renderDirty = false;
            return;
        }

        $texture = sdl_create_texture_from_surface($renderer, $surface);
        if (!$texture) {
            $this->renderDirty = false;
            return;
        }

        $dimensions = ttf_size_text($font, $this->glyph);
        if ($dimensions !== false) {
            $this->textureWidth = (int) $dimensions['w'];
            $this->textureHeight = (int) $dimensions['h'];
        } else {
            $this->textureWidth = $this->size;
            $this->textureHeight = $this->size;
        }

        sdl_set_texture_blend_mode($texture, SDL_BLENDMODE_BLEND);
        if (function_exists('sdl_set_texture_alpha_mod')) {
            sdl_set_texture_alpha_mod($texture, $a);
        }

        $this->texture = $texture;
        $this->renderDirty = false;
    }

    private function clearTexture(): void
    {
        if ($this->texture !== null) {
            sdl_destroy_texture($this->texture);
            $this->texture = null;
        }
    }

    private function resolveGlyph(string|int|\PHPNative\Tailwind\Data\Icon $icon): string
    {
        if ($icon instanceof \PHPNative\Tailwind\Data\Icon) {
            return mb_chr($icon->value, 'UTF-8');
        }

        if (is_int($icon)) {
            return mb_chr($icon, 'UTF-8');
        }

        if (mb_strlen($icon, 'UTF-8') === 1) {
            return $icon;
        }

        throw new \InvalidArgumentException('Icon must be a valid unicode codepoint or a single character string.');
    }
}
