<?php
// components/Ui/Badge.php
// Generic badge component with palette + variants

namespace Components\Ui;

use Components\Base;
use Components\Support\Palette;

class Badge
{
    /**
     * Render a generic badge.
     *
     * @param string $type     Semantic type (e.g., success, warning, danger, info, muted, brand, active, inactive)
     * @param string $label    Text to display inside the badge
     * @param array  $options  Supported keys:
     *                        - variant: 'outline' | 'solid' | 'soft' (default: 'outline')
     *                        - rounded: string (e.g. 'rounded', 'rounded-md'; default: 'rounded-full')
     *                        - token: palette token override (green, orange, red, blue, gray, brand, ...)
     *                        - color: palette token or utility classes (bg-*, text-*, ring-*, ...). If utilities, used directly.
     *                        - class: string (direct classes applied to inner badge; overrides palette variant classes)
     *                        - wrapper_class: string (extra classes for outer wrapper)
     *                        - inner_class: string (extra classes for inner badge)
     *                        - content_html: string (raw inner HTML; if provided, used instead of escaped label)
     *                        - title: string (wrapper title attribute)
     *                        - aria_label: string (wrapper aria-label attribute)
     *                        - icon: string (raw SVG markup to prepend; SVG is not modified)
     *                        - icon_class: string (utility classes for the icon; use "[&_svg]:..." for SVG targeting)
     *                        - icon_container_class: string (optional span wrapper for the icon)
     *                        - tag: string (wrapper tag, e.g. 'div' or 'button'; auto-detected when clickable if not provided)
     *                        - modal_url: string (convenience — open legacy URL in iframe modal)
     *                        - modal_hx_get: string (convenience — load BeezUI route into modal body via HTMX)
     *                        - modal_size: string (modal size token; default '3xl')
     *                        - panel_id: string (target modal/drawer id for convenience handlers)
     *                        - panel_target_id: string (target modal body id for convenience handlers)
     *                        - attrs: array (HTML attributes for wrapper; merged with defaults)
     * @return string
     */
    public static function render(string $type, string $label, array $options = []): string
    {
        $kind = strtolower(trim($type));

        // Map semantic types to palette tokens
        $tokenMap = [
            'success'  => 'green',
            'ok'       => 'green',
            'active'   => 'green',
            'warning'  => 'orange',
            'warn'     => 'orange',
            'inactive' => 'orange',
            'danger'   => 'red',
            'error'    => 'red',
            'fail'     => 'red',
            'info'     => 'blue',
            'brand'    => 'brand',
            'muted'    => 'gray',
            'secondary'=> 'gray',
            'primary'  => 'brand',
            'default'  => 'gray',
        ];

        $token   = isset($options['token']) && is_string($options['token']) && $options['token'] !== ''
            ? strtolower($options['token'])
            : ($tokenMap[$kind] ?? 'gray');
        $variant = strtolower((string)($options['variant'] ?? 'outline'));

        $providedClass = trim((string)($options['class'] ?? ''));
        $colorOpt      = trim((string)($options['color'] ?? ''));

        $pal = Palette::map();
        $isColorToken = $colorOpt !== '' && isset($pal[strtolower($colorOpt)]);

        // If color option is provided and it is a palette token, use it as token
        if ($isColorToken) {
            $token = strtolower($colorOpt);
        }

        $pt  = $pal[$token] ?? ($pal['gray'] ?? [
            'bg' => 'bg-gray-100', 'text' => 'text-gray-600', 'dot' => 'bg-gray-500', 'ring' => 'ring-gray-500'
        ]);

        // Build classes per variant unless caller provided explicit classes
        if ($providedClass !== '') {
            $badgeClass = $providedClass;
        } elseif ($colorOpt !== '' && !$isColorToken) {
            // Treat color with utility tokens as direct class override
            $badgeClass = $colorOpt;
        } else {
            switch ($variant) {
                case 'solid':
                    // Solid badges keep a subtle ring by default
                    $badgeClass = trim(($pt['dot'] ?? ($pt['bg'] ?? 'bg-gray-500')) . ' text-white ring-1 ring-white dark:ring-gray-900 gap-1  [&>svg]:size-4!');
                    break;
                case 'soft':
                    // Soft badges have no ring
                    $badgeClass = trim(($pt['bg'] ?? 'bg-gray-100') . ' ' . ($pt['text'] ?? 'text-gray-600') . ' ring-0 gap-1 [&>svg]:size-4!');
                    break;
                case 'outline':
                default:
                    // Outline badges explicitly include ring width
                    $badgeClass = trim('bg-transparent ring-1 ' . ($pt['ring'] ?? 'ring-gray-500') . ' ' . ($pt['text'] ?? 'text-gray-600 gap-1 [&>svg]:size-4!'));
                    break;
            }
        }

        $wrapperClass = trim((string)($options['wrapper_class'] ?? ''));
        $roundedClass = (string)($options['rounded'] ?? 'rounded-full');
        $innerClass   = trim('inline-flex items-center transform ' . $roundedClass . ' px-2 py-1 text-xs ring-0 ' . $badgeClass . ' ' . (string)($options['inner_class'] ?? ''));

        // Default wrapper attributes; allow overrides via options['attrs']
        $titleAttr = isset($options['title']) ? (string)$options['title'] : $label;
        $ariaAttr  = isset($options['aria_label']) ? (string)$options['aria_label'] : $label;
        $defaultAttrs = [
            'class'       => trim('inline-flex ' . $wrapperClass),
            'role'        => 'status',
            'title'       => Base::h($titleAttr),
            'aria-label'  => Base::h($ariaAttr),
        ];
        $attrs = $options['attrs'] ?? [];

        // Modal convenience handlers
        $panelId         = isset($options['panel_id']) && is_string($options['panel_id']) && $options['panel_id'] !== '' ? (string)$options['panel_id'] : null;
        $panelTargetId   = isset($options['panel_target_id']) && is_string($options['panel_target_id']) && $options['panel_target_id'] !== '' ? (string)$options['panel_target_id'] : null;
        $modalSize       = (string)($options['modal_size'] ?? '3xl');
        if (!empty($options['modal_url']) && is_string($options['modal_url'])) {
            $attrs = array_merge([
                'command'    => 'show-modal',
                'commandfor' => $panelId ?? '',
                'data-size'  => $modalSize,
                'data-url'   => (string)$options['modal_url'],
            ], is_array($attrs) ? $attrs : []);
        }
        if (!empty($options['modal_hx_get']) && is_string($options['modal_hx_get'])) {
            $at = [
                'command'    => 'show-modal',
                'commandfor' => $panelId ?? '',
                'data-size'  => $modalSize,
                'hx-get'     => (string)$options['modal_hx_get'],
            ];
            if ($panelTargetId) {
                $at['hx-target'] = '#' . ltrim($panelTargetId, '#');
                $at['hx-swap']   = 'innerHTML';
            }
            $attrs = array_merge($at, is_array($attrs) ? $attrs : []);
        }

        // Merge with preference to user-provided attributes
        $wrapperAttrs = array_merge($defaultAttrs, is_array($attrs) ? $attrs : []);

        // Build inner content
        $contentHtmlProvided = array_key_exists('content_html', $options) ? (string)$options['content_html'] : null;
        $content = $contentHtmlProvided !== null ? $contentHtmlProvided : Base::h($label);

        $icon                = (string)($options['icon'] ?? '');
        $iconClassRaw        = trim((string)($options['icon_class'] ?? ''));
        $iconContainerClass  = trim((string)($options['icon_container_class'] ?? ''));
        $iconCls             = $iconClassRaw;

        if ($icon !== '' && strpos($icon, '<svg') !== false) {
            $iconNode = $icon; // do not mutate SVG
            $spanCls = trim($iconContainerClass . ' ' . $iconCls);
            if ($spanCls !== '') {
                $iconNode = '<span class="' . Base::h($spanCls) . '">' . $iconNode . '</span>';
            }
            $content = $iconNode . ($content !== '' ? ' ' . $content : '');
        }


        $tag = isset($options['tag']) && is_string($options['tag']) && $options['tag'] !== ''
            ? (string)$options['tag']
            : ((isset($wrapperAttrs['command']) || isset($wrapperAttrs['hx-get']) || isset($wrapperAttrs['hx-post']) || isset($wrapperAttrs['href'])) ? 'button' : 'div');

        // Add @click.stop if clickable and not already set
        $isClickable = in_array($tag, ['button', 'a']) || isset($wrapperAttrs['hx-get']) || isset($wrapperAttrs['hx-post']) || isset($wrapperAttrs['command']) || isset($wrapperAttrs['href']);
        if ($isClickable && !isset($wrapperAttrs['@click.stop'])) {
            $wrapperAttrs['@click.stop'] = '';
        }

        ob_start();
        ?>
        <<?= $tag; ?> <?= Base::attrs($wrapperAttrs); ?>>
            <div <?= Base::attrs(['class' => $innerClass]); ?>>
                <?= $content; ?>
            </div>
        </<?= $tag; ?>>
        <?php
        return (string)ob_get_clean();
    }
}
