<?php
// components/CampaignFlow/StepCard.php
namespace Components\CampaignFlow;

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

class StepCard extends Base
{
    /**
     * Render a visual step card
     * $step keys:
     * - id (string)
     * - title (string)
     * - subtitle (string) optional
     * - icon (string) raw HTML (emoji or SVG markup)
     * - color (string) Tailwind utility classes applied to the icon wrapper, e.g. "bg-blue-100 text-blue-600".
     *           Backwards compatible: a simple color token like "blue"|"indigo"|"yellow"|"green"|"gray" still works.
     * - disabled (bool) optional: when true, card is shown with a visually disabled style and aria-disabled.
     * - markers (array) optional: list of marker objects describing top-right indicators
     *     marker object: ['color' => '<Tailwind classes or any CSS color>', 'label' => 'Tooltip text', 'icon' => '<raw SVG or emoji>']
     *   Also supported: 'marker' as a single object or string color for backwards compatibility.
     * - icon_indicators (array) optional: small colored dots overlaid on the module icon itself (not the card). Each item supports:
     *     ['color' => '<Tailwind bg-* classes, any CSS color, or palette token (blue|indigo|orange|yellow|green|gray|purple|red|pink|brand)>', 'label' => 'Tooltip text', 'pos' => 'tr|tl|br|bl']
     *   Also supported: 'icon_indicator' as a single object for convenience. When a palette token is used, the dot uses the palette's text tone converted to a bg tone (e.g., text-green-600 -> bg-green-600), falling back to the palette bg tone.
     * - href (string) optional: when provided, wraps the card with <a href="..."> making it clickable.
     * - attrs (array) optional: extra HTML attributes on the clickable wrapper (button or anchor) to support modal or htmx triggers.
     * - dropdown (array) optional: configuration for a Tailwind Plus Elements dropdown rendered as an options button.
     *     - trigger: ['label' => string, 'icon' => string, 'class' => string, 'attrs' => array]
     *     - items: list of menu item arrays: ['label' => string, 'attrs' => array, 'href' => string, 'icon' => string, 'divider' => bool]
     */
    public static function render(array $step, array $opts = []): string
    {
        $size = $opts['size'] ?? 'md'; // xs|sm|md|lg
        $editable = (bool)($opts['editable'] ?? false);

        $title = self::h($step['title'] ?? '');
        $subtitle = self::h($step['subtitle'] ?? '');
        $icon = $step['icon'] ?? self::SVG_MAIL;
        $isDisabled = (bool)($step['disabled'] ?? false);
        // Accept both 'color' (new) and legacy '_color'
        $color = trim((string)($step['color'] ?? ($step['_color'] ?? 'gray')));

        // Size classes
        $wrapBase = 'relative flex items-center bg-white ring ring-flow shrink-0 text-left';
        $sizes = [
            'xs' => ['wrap' => 'rounded-md p-1 pr-2 space-x-1 leading-none', 'iconWrap' => 'rounded-sm size-6 p-1', 'labelWrap' => '', 'title' => 'hidden', 'subtitle' => 'text-xs', 'markerWrap' => 'top-0.5 right-0.5', 'markerSize' => 'size-3'],
            'sm' => ['wrap' => 'rounded-lg p-1.5 pr-3 space-x-2 leading-none', 'iconWrap' => 'rounded-md size-8 p-1.5', 'labelWrap' => 'h-8 pt-0.5  ', 'title' => 'text-xs', 'subtitle' => 'text-[11px]', 'markerWrap' => 'top-1 right-1', 'markerSize' => 'size-3'],
            'md' => ['wrap' => 'rounded-xl p-2 pr-4 space-x-3 leading-none', 'iconWrap' => 'rounded-lg size-10 p-2', 'labelWrap' => 'h-10', 'title' => 'text-sm', 'subtitle' => 'text-xs', 'markerWrap' => 'top-1 right-1', 'markerSize' => 'size-4'],
            'lg' => ['wrap' => 'rounded-2xl p-2.5 pr-5 space-x-4 leading-none', 'iconWrap' => 'rounded-xl size-12 p-3', 'labelWrap' => 'h-12', 'title' => 'text-base', 'subtitle' => 'text-sm', 'markerWrap' => 'top-1.5 right-1.5', 'markerSize' => 'size-5'],
        ];
        $sz = $sizes[$size] ?? $sizes['md'];

        // Special visual treatment for the Trigger/Source steps: rounded-full wrapper and icon container
        $variant = isset($step['variant']) ? (string)$step['variant'] : '';
        $isTrigger = (($step['id'] ?? '') === 'trigger') || ($variant === 'trigger');
        $isSource = (($step['id'] ?? '') === 'source') || ($variant === 'source');
        $isRound = $isTrigger || $isSource;
        if ($isRound) {
            // Replace any rounded-* with rounded-full in wrapper and iconWrap size presets
            foreach (['wrap', 'iconWrap'] as $rk) {
                if (!empty($sz[$rk]) && is_string($sz[$rk])) {
                    $sz[$rk] = preg_replace('/\brounded-[^\s]+/i', 'rounded-full', $sz[$rk]);
                    if ($sz[$rk] === null) { $sz[$rk] = 'rounded-full'; }
                }
            }
        }

        // Shared color palette map
        $paletteMap = Palette::map();

        // If this is the special Trigger card and no explicit color provided, prefer green palette by default
        $hasExplicitColor = array_key_exists('color', $step) || array_key_exists('_color', $step);
        if (($isTrigger ?? false) && !$hasExplicitColor) {
            $color = 'green';
        }
        // If Source card without explicit color, prefer green as well
        if (($isSource ?? false) && !$hasExplicitColor) {
            $color = 'green';
        }

        // Resolve wrapper color classes from token or pass-through utilities
        $colorClasses = Palette::classes($color, 'gray');

        // Normalize markers input
        $markers = [];
        if (isset($step['markers'])) {
            $m = $step['markers'];
            if (is_array($m) && isset($m['color'])) {
                $markers = [$m];
            } elseif (is_array($m)) {
                foreach ($m as $it) {
                    if (is_string($it)) {
                        $markers[] = ['color' => $it];
                    } elseif (is_array($it)) {
                        $markers[] = $it;
                    }
                }
            }
        } elseif (isset($step['marker'])) {
            $m = $step['marker'];
            if (is_string($m)) {
                $markers = [['color' => $m]];
            } elseif (is_array($m)) {
                $markers = [$m];
            }
        }

        // Normalize icon indicators input (colored dots on the icon itself)
        $iconIndicators = [];
        if (isset($step['icon_indicators'])) {
            $ii = $step['icon_indicators'];
            if (is_array($ii) && isset($ii['color'])) {
                $iconIndicators = [$ii];
            } elseif (is_array($ii)) {
                foreach ($ii as $it) {
                    if (is_string($it)) {
                        $iconIndicators[] = ['color' => $it];
                    } elseif (is_array($it)) {
                        $iconIndicators[] = $it;
                    }
                }
            }
        } elseif (isset($step['icon_indicator'])) {
            $ii = $step['icon_indicator'];
            if (is_string($ii)) {
                $iconIndicators = [['color' => $ii]];
            } elseif (is_array($ii)) {
                $iconIndicators = [$ii];
            }
        }

        $wrapCls = trim($wrapBase . ' ' . $sz['wrap'] . ' ' . ($opts['class'] ?? ''));
        if ($isDisabled) {
            $wrapCls .= ' ' . self::DISABLED_CLASSES;
        }
        // Mouseover feedback for interactive cards
        // Add only when the step is clickable (href/attrs/dropdown) and not disabled
        $willHaveDropdown = !empty($step['dropdown']) && is_array($step['dropdown']);
        $hasAttrs = !empty($step['attrs']) && is_array($step['attrs']);
        $hasHref = isset($step['href']) && (string)$step['href'] !== '';
        $isInteractive = !$isDisabled && ($hasHref || $hasAttrs || $willHaveDropdown);
        if ($isInteractive) {
            $wrapCls .= ' ' . self::HOVER_CLICKABLE;
        }

        $iconWrapCls = 'relative flex items-center justify-center ' . $sz['iconWrap'] . ' '  . trim($colorClasses);
        $titleCls = $sz['title'] . ' font-medium truncate max-w-[12rem]';
        $subtitleCls = $sz['subtitle'];

        // Optional edit affordance (lg only)
        $editBtn = '';
        if ($editable && $size === 'lg') {
            $editBtn = '<button type="button" class="ml-2 rounded p-1 text-gray-400 hover:text-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-300" title="Configure step" aria-label="Configure step">'
                . '<svg class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8Z"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06A2 2 0 1 1 7.04 3.3l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9c0 .69.28 1.35.78 1.82.5.47 1.18.74 1.88.74H21a2 2 0 1 1 0 4h-.09c-.69 0-1.35.28-1.82.78Z"/></svg>'
                . '</button>';
        }

        $iconHtml = is_string($icon) ? $icon : '';

        $size = $sz['labelWrap'] ;

        $labelDivCls = stristr($sz['title'] , 'hidden') ? 'min-w-0 ' : 'flex flex-col justify-between min-w-0';
        $labelDivCls .=  ' ' . $size;

        // Clickable wrapper support
        $href = isset($step['href']) ? (string)$step['href'] : '';
        $extraAttrs = is_array($step['attrs'] ?? null) ? $step['attrs'] : [];
        $hasDropdown = !empty($step['dropdown']) && is_array($step['dropdown']);
        // Avoid nested interactive elements: if a dropdown is present, force a non-interactive wrapper (div)
        $outerTag = ($href !== '' && !$hasDropdown) ? 'a' : ((!empty($extraAttrs) && !$hasDropdown) ? 'button' : 'div');
        $outerAttrs = ['class' => $wrapCls];
        if ($href !== '' && $outerTag === 'a') {
            $outerAttrs['href'] = $href;
        }
        if ($outerTag === 'button') {
            $outerAttrs['type'] = $outerAttrs['type'] ?? 'button';
        }
        if ($isDisabled) {
            $outerAttrs['aria-disabled'] = 'true';
            if ($outerTag === 'button') {
                $outerAttrs['disabled'] = true;
            }
        }
        // Merge additional attributes (e.g., command, hx-*)
        foreach ($extraAttrs as $k => $v) {
            $outerAttrs[$k] = $v;
        }
        $outerAttrStr = self::attrs($outerAttrs);

        $iconWrapEsc = self::h($iconWrapCls);
        $subtitleHtml = $subtitle !== '' ? '<p class="text-secondary max-w-48 truncate ' . self::h($subtitleCls) . '">' . $subtitle . '</p>' : '';
        $titleHtml = $title !== '' ? '<p class="text-primary max-w-48 truncate ' . self::h($titleCls) . '">' . $title . '</p>' : '';

        // Build markers HTML if any
        $markersHtml = '';
        if (!empty($markers)) {
            $mWrapPos = self::h('absolute ' . $sz['markerWrap']);
            $mItems = '';
            foreach ($markers as $mk) {
                $mColorRaw = trim((string)($mk['color'] ?? ''));
                $mSizeCls = $sz['markerSize'];
                $titleAttr = '';
                if (!empty($mk['label'])) {
                    $titleAttr = ' title="' . self::h((string)$mk['label']) . '" aria-label="' . self::h((string)$mk['label']) . '"';
                }

                // Determine background via Tailwind classes or fallback to inline CSS color
                $mIsUtility = $mColorRaw !== '' && (preg_match('/\b(bg|text|from|to|via|fill|stroke|ring|border)-/i', $mColorRaw) || strpos($mColorRaw, ' ') !== false);
                $mClass = 'inline-flex items-center justify-center rounded-sm  ' . $mSizeCls;
                $mStyle = '';
                if ($mColorRaw === '') {
                    $mClass .= ' bg-flow';
                } elseif ($mIsUtility) {
                    $mClass .= ' ' . $mColorRaw;
                } else {
                    $mStyle = ' style="background-color:' . self::h($mColorRaw) . '"';
                }

                // Optional icon inside marker
                $markerIconHtml = '';
                if (!empty($mk['icon']) && is_string($mk['icon'])) {
                    $markerIconHtml = (string)$mk['icon'];
                    // Derive a slightly smaller icon size from the marker size (e.g., size-5 -> size-4)
                    $iconSize = $mSizeCls;
                    if (preg_match('/size-(\d+)/', $mSizeCls, $mm)) {
                        $n = max(1, ((int)$mm[1]) - 1);
                        $iconSize = 'size-' . $n;
                    }
                    // Inject a size class into the SVG if possible; otherwise wrap in a span for emoji
                    if (strpos($markerIconHtml, '<svg') !== false) {
                        if (strpos($markerIconHtml, 'class=') !== false) {
                            $markerIconHtml = preg_replace('/class=\"([^\"]*)\"/i', 'class="$1 ' . self::h($iconSize) . '"', $markerIconHtml, 1);
                        } else {
                            $markerIconHtml = preg_replace('/<svg\b/i', '<svg class="' . self::h($iconSize) . '"', $markerIconHtml, 1);
                        }
                    } else {
                        // Emoji or text: scale using a span
                        $markerIconHtml = '<span class=" ' . self::h($iconSize) . ' leading-none flex items-center justify-center">' . $markerIconHtml . '</span>';
                    }
                }

                $mItems .= '<div class=" p-0.5 ' . self::h($mClass) . '"' . $mStyle . $titleAttr . '>' . $markerIconHtml . '</div>';
            }
            $markersHtml = '<div class="' . $mWrapPos . ' flex items-center gap-1">' . $mItems . '</div>';
        }

        // Build icon indicators HTML (dots on the icon itself)
        $iconIndicatorsHtml = '';
        if (!empty($iconIndicators)) {
            // derive a dot size slightly smaller than the card marker size
            $dotSize = $sz['markerSize'];
            if (preg_match('/size-(\d+)/', $dotSize, $mm)) {
                $n = max(1, ((int)$mm[1]) - 1);
                $dotSize = 'size-' . $n;
            }
            foreach ($iconIndicators as $ii) {
                $iColorRaw = trim((string)($ii['color'] ?? ''));
                $pos = strtolower((string)($ii['pos'] ?? 'tr'));
                $titleAttr = '';
                if (!empty($ii['label'])) {
                    $titleAttr = ' title="' . self::h((string)$ii['label']) . '" aria-label="' . self::h((string)$ii['label']) . '"';
                }
                // Position the indicator inside the icon wrapper (on the SVG), offset by the wrapper padding
                $offset = '2';
                if (preg_match('/\bp-([0-9]+(?:\.[0-9]+)?)/', $sz['iconWrap'], $mPad)) { $offset = (string)($mPad[1] - 0.5); }
                $posCls = 'top-' . $offset . ' right-' . $offset;
                if ($pos === 'tl') { $posCls = 'top-' . $offset . ' left-' . $offset; }
                elseif ($pos === 'br') { $posCls = 'bottom-' . $offset . ' right-' . $offset; }
                elseif ($pos === 'bl') { $posCls = 'bottom-' . $offset . ' left-' . $offset; }

                $baseCls = 'absolute block transform rounded-full  dark:ring-gray-900 ' . $dotSize . ' ' . $posCls;
                $style = '';
                if ($iColorRaw === '') {
                    $baseCls .= ' bg-red-500';
                } else {
                    $isUtility = preg_match('/\b(bg|text|from|to|via|fill|stroke|ring|border)-/i', $iColorRaw) || strpos($iColorRaw, ' ') !== false;
                    if ($isUtility) {
                        $baseCls .= ' ' . $iColorRaw;
                    } else {
                        // Try palette token first
                        if (isset($paletteMap[$iColorRaw])) {
                            $dotClsFromPalette = Palette::dotBg($iColorRaw, 'gray');
                            if ($dotClsFromPalette !== '') {
                                $baseCls .= ' ' . $dotClsFromPalette;
                            } else {
                                $baseCls .= ' bg-red-500';
                            }
                        } else {
                            // Treat as raw CSS color (e.g., #ff9900)
                            $style = ' style="background-color:' . self::h($iColorRaw) . '"';
                        }
                    }
                }
                $iconIndicatorsHtml .= '<span class="' . self::h($baseCls) . '"' . $style . $titleAttr . '></span>';
            }
        }

        // Optional dropdown menu � collect config; actual rendering delegated to Components\Dropdown
        $dropdownWrapStart = '';
        $dropdownWrapEnd = '';
        $useDropdown = !empty($step['dropdown']) && is_array($step['dropdown']);
        $dropdownItems = [];
        $dropdownTriggerAttrs = [];
        if ($useDropdown) {
            $dd = $step['dropdown'];
            $tr = is_array($dd['trigger'] ?? null) ? $dd['trigger'] : [];
            $dropdownItems = is_array($dd['items'] ?? null) ? $dd['items'] : [];
            $dropdownTriggerAttrs = is_array($tr['attrs'] ?? null) ? $tr['attrs'] : [];
            // Do not modify $outerTag/$outerAttrs here; Dropdown will handle trigger/button wrapping
        }

        // Assemble card inner content
        $cardInner = <<<HTML
  <div class="$iconWrapEsc">$iconHtml$iconIndicatorsHtml</div>
  <div class="$labelDivCls">
    $subtitleHtml
    $titleHtml
  </div>
  $editBtn
  $markersHtml
HTML;

        // Final outer structure � delegate dropdown rendering to Components\Dropdown when configured
        if ($useDropdown) {
            $triggerAttrs = ['class' => $wrapCls, 'type' => 'button'];
            if ($isDisabled) { $triggerAttrs['aria-disabled'] = 'true'; $triggerAttrs['disabled'] = true; }
            foreach ($dropdownTriggerAttrs as $k => $v) { $triggerAttrs[$k] = $v; }
            $html = \Components\Dropdown::render([
                'trigger_tag' => 'button',
                'trigger_attrs' => $triggerAttrs,
                'trigger_html' => $cardInner,
                'items' => $dropdownItems,
                'anchor' => 'bottom start',
                'popover' => 'manual',
                'wrapper_class' => 'inline-flex relative',
            ]);
            return $html;
        }

        $html = <<<HTML
<{$outerTag}{$outerAttrStr}>
$cardInner</{$outerTag}>
HTML;
        return $html;
    }
}
