<?php
// components/Assistant/ChatBubble.php
namespace Components\Assistant;

use Components\Base;

class ChatBubble
{
    /**
     * Render the bot question bubble.
     * Keeps original classes to avoid visual regressions.
     * Adds wordReveal effect for assistant messages (bot bubbles).
     */
    public static function renderBot(string $label, array $wrapperAttrs = []): string
    {
        // Escape the label for safe HTML output inside the hidden source. If rich HTML is desired in future,
        // this can be adjusted to allow a safe subset.
        $labelEsc = Base::h($label);
        // Wrapper attributes and classes
        $wrapperClass = 'flex items-start gap-3';
        if (!empty($wrapperAttrs['class'])) {
            $wrapperClass = trim($wrapperClass . ' ' . (string)$wrapperAttrs['class']);
            unset($wrapperAttrs['class']);
        }
        // Capture reveal flag before removing it from attributes so we can use it internally
        $__revealFlag = !empty($wrapperAttrs['reveal']);
        // Support deferred reveal start controlled externally (e.g., after explainer finishes)
        $__deferFlag = !empty($wrapperAttrs['defer_reveal']) || array_key_exists('data-defer-reveal', $wrapperAttrs);
        // Remove internal-only flags from being rendered as HTML attributes
        if (array_key_exists('reveal', $wrapperAttrs)) {
            unset($wrapperAttrs['reveal']);
        }
        if (array_key_exists('defer_reveal', $wrapperAttrs)) {
            unset($wrapperAttrs['defer_reveal']);
        }
        $wrapperPairs = [];
        $wrapperPairs[] = 'class="' . Base::h($wrapperClass) . '"';
        foreach ($wrapperAttrs as $k => $v) {
            if ($v === '') {
                $wrapperPairs[] = Base::h((string)$k);
            } else {
                $wrapperPairs[] = Base::h((string)$k) . '="' . Base::h((string)$v) . '"';
            }
        }
        $wrapperAttr = implode(' ', $wrapperPairs);

        ob_start();
        ?>
<div <?= $wrapperAttr ?>>
  <div class="rounded-2xl rounded-tl-sm bg-brand-50 px-4 py-2 text-sm text-brand-900 dark:bg-brand-900/20 dark:text-brand-100">
    <?php $reveal = $__revealFlag; ?>
    <?php if ($reveal): ?>
      <!-- Word reveal container (only for newest/current bot message) -->
      <?php if ($__deferFlag): ?>
        <span x-data="wordReveal()" x-init="(() => { const el = $el; let started=false; const h = (ev) => { try { if (ev && (ev.target === el || (ev.detail && (ev.detail === 'all' || ev.detail.el === el)))) { if (!started) { start(el); started=true; document.removeEventListener('assistant:reveal', h, false); } } } catch (e) { if (!started) { start(el); started=true; document.removeEventListener('assistant:reveal', h, false); } } }; document.addEventListener('assistant:reveal', h, false); })()" data-reveal-root>
          <span x-html="visible"></span>
          <!-- Hidden source with the full message -->
          <span class="hidden" data-source><?= $labelEsc ?></span>
        </span>
      <?php else: ?>
        <span x-data="wordReveal()" x-init="start($el)" data-reveal-root>
          <span x-html="visible"></span>
          <!-- Hidden source with the full message -->
          <span class="hidden" data-source><?= $labelEsc ?></span>
        </span>
      <?php endif; ?>
    <?php else: ?>
      <?= $labelEsc ?>
    <?php endif; ?>
  </div>
</div>
<?php
        return ob_get_clean();
    }

    /**
     * Render the user answer bubble.
     * By default adds data-answer-bubble attribute like the original markup.
     */
    public static function renderUser(string $text, array $attrs = []): string
    {
        $textEsc = Base::h($text);

        // Ensure wrapper class present and data-answer-bubble preserved
        $wrapperClass = 'flex justify-end';
        if (!empty($attrs['wrapperClass'])) {
            $wrapperClass = trim($wrapperClass . ' ' . (string)$attrs['wrapperClass']);
            unset($attrs['wrapperClass']);
        }

        // Inner DIV attributes
        $innerClass = 'rounded-2xl rounded-tr-sm bg-brand px-4 py-2 text-sm text-white';
        if (!empty($attrs['class'])) {
            $innerClass = trim($innerClass . ' ' . (string)$attrs['class']);
            unset($attrs['class']);
        }

        // Keep data-answer-bubble unless explicitly disabled
        $dataAttrs = ['data-answer-bubble' => ''];
        if (isset($attrs['data'])) {
            // Merge extra data-* attributes
            foreach ((array)$attrs['data'] as $k => $v) {
                $dataAttrs['data-' . $k] = (string)$v;
            }
            unset($attrs['data']);
        }
        if (array_key_exists('answerBubble', $attrs)) {
            if ($attrs['answerBubble'] === false) {
                unset($dataAttrs['data-answer-bubble']);
            }
            unset($attrs['answerBubble']);
        }

        // Build attribute string for inner DIV
        $attrPairs = [];
        $attrPairs[] = 'class="' . Base::h($innerClass) . '"';
        foreach ($dataAttrs as $k => $v) {
            if ($v === '') {
                $attrPairs[] = Base::h($k);
            } else {
                $attrPairs[] = Base::h($k) . '="' . Base::h($v) . '"';
            }
        }
        // Any leftover attributes passed directly
        foreach ($attrs as $k => $v) {
            $attrPairs[] = Base::h((string)$k) . '="' . Base::h((string)$v) . '"';
        }
        $innerAttr = implode(' ', $attrPairs);

        ob_start();
        ?>
<div class="<?= Base::h($wrapperClass) ?>">
  <div <?= $innerAttr ?>>
    <?= $textEsc ?>
  </div>
</div>
<?php
        return ob_get_clean();
    }
}
