<?php
// components/Form/RadioCards.php
namespace Components\Form;

class RadioCards extends RadioBase {

    /**
     * Render a radio-card group similar to Tailwind UI example
     * $options: array where key is value and item is:
     *   - string label
     *   - or array{label: string, description?: string, meta?: string, aria_label?: string, aria_description?: string}
     */
    public static function render(string $name, string $label, array $options, $value = '', array $opts = []): string {
        $ctx = self::buildRadioFieldContext($name, $label, $opts);
        $extra = $ctx['extra_attrs'];
        $badge = $ctx['badge_html'];
        // Optional layout: dynamic cards-per-row per breakpoint
        $gridCfg = $opts['grid'] ?? [];

        $nameEsc = $ctx['name_esc'];
        $labelEsc = $ctx['label_esc'];
        $helpHtml = $ctx['help_html'];
        $errorHtml = $ctx['error_html'];
        $clientErr = $ctx['client_err_html'];

        $requiredAttr = $ctx['required_attr'];
        $groupErrorClass = $ctx['group_error_class'];
        // Build cards
        $cards = '';
        $items = self::normalizeOptions($options, $value);
        foreach ($items as $item) {
            $valEsc = self::h($item['value']);
            $optLabelEsc = self::h($item['label']);
            $optDescEsc = self::h($item['description']);
            $optMetaEsc = self::h($item['meta']);
            $ariaLabelEsc = self::h($item['aria_label']);
            $ariaDescEsc = self::h($item['aria_description']);
            $checkedAttr = (string)$item['checked_attr'];
            // Optional meta line: render only when non-empty (after escaping & trim)
            $metaHtml = (trim($optMetaEsc) !== '')
                ? '<span class="mt-6 block text-sm font-medium text-gray-900 dark:text-white">' . $optMetaEsc . '</span>'
                : '';

            $iconHtml = self::renderOptionIcon((string)$item['icon'], (string)$item['token']);

            $applicability = $item['applicability'] ?? null;
            $appShowAttr = '';
            $appInputAttr = '';
            if (is_array($applicability)) {
                $appJs = htmlspecialchars(json_encode($applicability), ENT_QUOTES);
                $isApp = 'typeof isSourceApplicable === \'function\' ? isSourceApplicable(' . $appJs . ') : true';
                $mode = $opts['applicability_mode'] ?? 'hide';
                if ($mode === 'disable') {
                    $appInputAttr = ' :disabled="!(' . $isApp . ')" :class="!(' . $isApp . ') ? \'pointer-events-none\' : \'\'"';
                } else {
                    $appShowAttr = ' x-show="' . $isApp . '" x-cloak';
                }
            }

            $cardClass = self::radioCardClass();

            // Each card is a label containing the input and the content
            $cards .= <<<HTML
<label{$appShowAttr} aria-label="{$ariaLabelEsc}" aria-description="{$ariaDescEsc}" class="{$cardClass}">
  <input type="radio" name="{$nameEsc}" value="{$valEsc}" class="absolute inset-0 appearance-none focus:outline-none"{$checkedAttr}{$requiredAttr} {$extra}{$appInputAttr} />
  {$iconHtml}
  <div class="flex-1">
    <span class="block text-sm font-medium text-gray-900 dark:text-white">{$optLabelEsc}</span>
    <!-- description -->
    <span class="mt-1 block text-sm text-gray-500 dark:text-gray-400">{$optDescEsc}</span>
    <!-- meta (optional) -->
    {$metaHtml}
  </div>
  <svg viewBox="0 0 20 20" fill="currentColor" data-slot="icon" aria-hidden="true" class="invisible size-5 text-brand group-has-checked:visible dark:text-brand">
    <path d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm3.857-9.809a.75.75 0 0 0-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 1 0-1.06 1.061l2.5 2.5a.75.75 0 0 0 1.137-.089l4-5.5Z" clip-rule="evenodd" fill-rule="evenodd" />
  </svg>
</label>
HTML;
        }

        $labelHtml = '';
        if (!($opts['no_label'] ?? false)) {
            $labelHtml = self::renderLabel('', $label, $badge, $opts);
        }

        $gridClasses = self::buildGridClasses($gridCfg, 1, 3);
        $containerClass = $ctx['container_class'];

        // Wrap in fieldset with legend and grid
        return <<<HTML
<fieldset class="{$containerClass} {$groupErrorClass} min-w-0">
  <legend class="contents">{$labelHtml}</legend>
  <div class="mt-2 {$gridClasses}">
    {$cards}
  </div>
  {$helpHtml}
  {$errorHtml}
  {$clientErr}
</fieldset>
HTML;
    }

    /**
     * Render grouped radio cards with section headers and optional explainer text per group.
     * Expected $groups shape:
     *   [
     *     [
     *       'label' => 'Customers',
     *       'help'  => 'Existing customers in your shop', // optional
     *       'items' => [
     *         ['id' => 'code', 'text' => 'Label', 'description' => '...'],
     *         // or 'value'/'label' keys
     *       ]
     *     ],
     *     ...
     *   ]
     */
    public static function renderGrouped(string $name, string $label, array $groups, $value = '', array $opts = []): string
    {
        $ctx = self::buildRadioFieldContext($name, $label, $opts);
        $extra = $ctx['extra_attrs'];
        $badge = $ctx['badge_html'];
        // Optional layout: dynamic cards-per-row per breakpoint
        $gridCfg = $opts['grid'] ?? [];

        $nameEsc = $ctx['name_esc'];
        $labelEsc = $ctx['label_esc'];
        $helpHtml = $ctx['help_html'];
        $errorHtml = $ctx['error_html'];
        $clientErr = $ctx['client_err_html'];

        $requiredAttr = $ctx['required_attr'];
        $groupErrorClass = $ctx['group_error_class'];

        $current = (string)$value;

        // Prepare groups with stable keys and detect which group contains the current value
        $prepared = [];
        $currentGroupKey = '';
        $groupFirst = [];
        foreach ($groups as $g) {
            if (!is_array($g)) { continue; }
            $gLabel = self::lng((string)($g['label'] ?? ''));
            $gHelp  = self::lng((string)($g['help'] ?? ''));
            $items  = is_array($g['items'] ?? null) ? $g['items'] : [];
            $keyRaw = (string)($g['key'] ?? '');
            $gIcon  = (string)($g['icon'] ?? '');
            $gActive = !empty($g['active']);
            if ($keyRaw === '') {
                $keyRaw = strtolower(preg_replace('/[^a-z0-9]+/i', '_', $gLabel));
                $keyRaw = trim($keyRaw, '_');
            }

            $cards = '';
            $containsCurrent = false;
            $firstValThisGroup = '';
            foreach ($items as $it) {
                if (!is_array($it)) { continue; }

                $normalized = self::normalizeGroupedOption($it, $current);
                if (!is_array($normalized)) { continue; }

                $valStr = (string)$normalized['value'];
                if ($firstValThisGroup === '') { $firstValThisGroup = $valStr; }
                if ($current !== '' && $current === $valStr) { $containsCurrent = true; }

                $valEsc = self::h($valStr);
                $optLabelEsc = self::h((string)$normalized['label']);
                $optDescEsc = self::h((string)$normalized['description']);
                $optMetaEsc = self::h((string)$normalized['meta']);
                $checkedAttr = (string)$normalized['checked_attr'];
                // Optional meta line: render only when non-empty (after escaping & trim)
                $metaHtml = (trim($optMetaEsc) !== '')
                    ? '<span class="mt-6 block text-sm font-medium text-gray-900 dark:text-white">' . $optMetaEsc . '</span>'
                    : '';

                $iconHtml = self::renderOptionIcon((string)$normalized['icon'], (string)$normalized['token']);

                $applicability = $it['applicability'] ?? null;
                $appShowAttr = '';
                $appInputAttr = '';
                if (is_array($applicability)) {
                    $appJs = htmlspecialchars(json_encode($applicability), ENT_QUOTES);
                    $isApp = 'typeof isSourceApplicable === \'function\' ? isSourceApplicable(' . $appJs . ') : true';
                    $mode = $opts['applicability_mode'] ?? 'hide';
                    if ($mode === 'disable') {
                        $appInputAttr = ' :disabled="!(' . $isApp . ')" :class="!(' . $isApp . ') ? \'pointer-events-none\' : \'\'"';
                    } else {
                        $appShowAttr = ' x-show="' . $isApp . '" x-cloak';
                    }
                }

                $cardClass = self::radioCardClass();

                $cards .= <<<HTML
<label{$appShowAttr} class="{$cardClass}">
  <input type="radio" name="{$nameEsc}" value="{$valEsc}" class="absolute inset-0 appearance-none focus:outline-none"{$checkedAttr}{$requiredAttr} {$extra}{$appInputAttr} />
  {$iconHtml}
  <div class="flex-1">
    <span class="block text-sm font-medium text-gray-900 dark:text-white">{$optLabelEsc}</span>
    <span class="mt-1 block text-sm text-gray-500 dark:text-gray-400">{$optDescEsc}</span>
    {$metaHtml}
  </div>
  <svg viewBox="0 0 20 20" fill="currentColor" data-slot="icon" aria-hidden="true" class="invisible size-5 text-brand group-has-checked:visible dark:text-brand"><path d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm3.857-9.809a.75.75 0 0 0-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 1 0-1.06 1.061l2.5 2.5a.75.75 0 0 0 1.137-.089l4-5.5Z" clip-rule="evenodd" fill-rule="evenodd" /></svg>
</label>
HTML;
            }

            if ($containsCurrent) { $currentGroupKey = $keyRaw; }
            if ($firstValThisGroup !== '') { $groupFirst[$keyRaw] = $firstValThisGroup; }

            $prepared[] = [
                'key'   => $keyRaw,
                'label' => $gLabel,
                'help'  => $gHelp,
                'icon'  => $gIcon,
                'active'=> $gActive,
                'cards' => $cards,
            ];
        }

        // Default tab: prefer the group containing the current value; otherwise a group marked as active; else the first one
        $defaultTab = '';
        if ($currentGroupKey !== '') {
            $defaultTab = $currentGroupKey;
        } else {
            foreach ($prepared as $p) {
                if (!empty($p['active'])) { $defaultTab = (string)$p['key']; break; }
            }
            if ($defaultTab === '') {
                $defaultTab = (count($prepared) > 0) ? (string)$prepared[0]['key'] : '';
            }
        }
        $defaultTabJs = htmlspecialchars(json_encode($defaultTab, JSON_UNESCAPED_UNICODE), ENT_QUOTES);
        $lockedKeyJs  = htmlspecialchars(json_encode($currentGroupKey, JSON_UNESCAPED_UNICODE), ENT_QUOTES);
        $groupFirstJs = htmlspecialchars(json_encode($groupFirst, JSON_UNESCAPED_UNICODE), ENT_QUOTES);
        $nameJs = htmlspecialchars(json_encode((string)$name), ENT_QUOTES);

        // Locked-state explainer: prefer caller-provided message; else use a neutral, UI-generic default
        $lockMsgRaw = (string)($opts['locked_message'] ?? '');
        if ($lockMsgRaw === '') {
            // Generic default (component-level, not model-specific)
            $lockMsgRaw = (string)\mh_lng(
                'MAILBEEZ_FORM_FIELD_SELECTION_LOCKED',
                'Selection for this field is locked and cannot be changed in edit mode.'
            );
        }
        $lockMsg = self::lng($lockMsgRaw);
        $lockMsgEsc = self::h($lockMsg);

        // Prepare Tabs items (value/label/icon)
        $tabItems = [];
        foreach ($prepared as $p) {
            $tabItems[] = [
                'value' => (string)$p['key'],
                'label' => (string)$p['label'],
                'icon'  => (string)($p['icon'] ?? ''),
            ];
        }

        // Render Tabs using shared UI component (desktop with icons + mobile select)
        $tabsMobile  = \Components\Ui\Tabs::mobile('active', $tabItems, [
            'ariaLabel' => 'Select a tab',
            'onChange'  => 'setTab(active)'
        ]);
        $tabsDesktop = \Components\Ui\Tabs::desktop('active', $tabItems, [
            'onClick' => 'setTab({value})'
        ]);

        // Build bodies per tab
        $bodies = '';
        foreach ($prepared as $p) {
            $k = self::h((string)$p['key']);
            $gHelpEsc = self::h((string)$p['help']);
            $helpBlock = $p['help'] !== '' ? ("<p class=\"mt-1 text-sm text-secondary\">{$gHelpEsc}</p>") : '';
            $cardsHtml = (string)$p['cards'];
            $gridClasses = self::buildGridClasses($gridCfg, 1, 3);
            $cardsHtml = $cardsHtml === '' ? '' : ("<div class=\"mt-2 {$gridClasses}\">{$cardsHtml}</div>");
            $bodies .= <<<HTML
<div x-show="active==='{$k}'" x-ref="panel-{$k}" data-panel="1" data-key="{$k}" class="absolute inset-0 px-0 py-0" x-transition.opacity.duration.200ms>
  {$helpBlock}
  <template x-if="!locked || locked===active">
    <div>{$cardsHtml}</div>
  </template>
  <template x-if="locked && locked!==active">
    <div class="mt-2 rounded-md border border-dashed border-gray-300 bg-gray-50 p-3 text-sm text-secondary dark:border-white/10 dark:bg-gray-800/40">{$lockMsgEsc}</div>
  </template>
</div>
HTML;
        }

        $containerClass = $ctx['container_class'];
        return <<<HTML
<fieldset class="{$containerClass} {$groupErrorClass}">
  <legend class="text-sm/6 font-semibold text-gray-900 dark:text-white">{$labelEsc}{$badge}</legend>
  <div x-data="{
        active: {$defaultTabJs},
        locked: {$lockedKeyJs},
        first: {$groupFirstJs},
        name: {$nameJs},
        containerHeight: 0,
        _setValue(v){ try{ var list = document.querySelectorAll('input[type=radio][name=\''+this.name+'\']'); var found=null; list.forEach(function(inp){ if(String(inp.value)===String(v)){ found = inp; } }); if(found){ if(!found.checked){ found.checked = true; found.dispatchEvent(new Event('change', { bubbles: true })); } } }catch(e){} },
        updateHeight(){ try { var el = this.\$refs['panel-' + this.active]; if (el) { this.containerHeight = el.scrollHeight; } } catch(e){} },
        setTab(k){
          this.active = k;
          if(!this.locked || this.locked===k){
            var v = this.first && this.first[k] ? this.first[k] : '';
            if(v){ this._setValue(v); }
          }
          this.\$nextTick(() => { this.updateHeight(); });
        }
      }"
       x-init="(() => { try { var anyChecked = !!document.querySelector('input[type=radio][name=\''+name+'\']:checked'); if (!anyChecked && (!locked || locked===active)) { var v = first && first[active] ? first[active] : ''; if (v) { _setValue(v); } } } catch(e){}; \$nextTick(() => { updateHeight(); }); })()"
       class="mt-1">
    <!-- Mobile: select -->
    {$tabsMobile}

    <!-- Desktop: tabs nav -->
    {$tabsDesktop}
    <div class="mt-3 relative overflow-hidden" x-ref="panelsWrap" x-on:resize.window="updateHeight()" x-bind:style="'height:'+containerHeight+'px; transition: height 250ms cubic-bezier(0.4, 0, 0.2, 1);'">
      {$bodies}
    </div>
  </div>
  {$helpHtml}
  {$errorHtml}
  {$clientErr}
</fieldset>
HTML;
    }
}
