<?php
// components/Ui/Tabs.php
namespace Components\Ui;

use Components\Base;

class Tabs
{
    /**
     * Render a mobile <select> tabs switcher bound to an Alpine.js model.
     *
     * @param string $model   Alpine model name (e.g., 'tab' or 'activeTab') present on an ancestor x-data
     * @param array  $items   List of [ ['value' => 'id', 'label' => 'Title'], ... ]
     * @param array  $opts    Optional: ['ariaLabel' => 'Select a tab']
     */
    public static function mobile(string $model, array $items, array $opts = []): string
    {
        $aria = isset($opts['ariaLabel']) ? (string)$opts['ariaLabel'] : 'Select a tab';
        $ariaEsc = Base::h((string) $aria);
        $onChange = isset($opts['onChange']) ? (string)$opts['onChange'] : '';

        $options = '';
        foreach ($items as $it) {
            if (!is_array($it)) { continue; }
            $val = isset($it['value']) ? (string)$it['value'] : '';
            $lab = isset($it['label']) ? (string)$it['label'] : $val;
            if ($val === '') { continue; }
            $options .= '<option value="' . Base::h($val) . '">' . Base::h($lab) . '</option>';
        }

        $chev = '<svg viewBox="0 0 16 16" fill="currentColor" data-slot="icon" aria-hidden="true"'
              . ' class="pointer-events-none col-start-1 row-start-1 mr-2 size-5 self-center justify-self-end fill-secondary">'
              . '<path d="M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" fill-rule="evenodd"/></svg>';

        $changeAttr = $onChange !== '' ? (' @change="' . $onChange . '"') : '';

        return <<<HTML
<div class="grid grid-cols-1 sm:hidden">
  <select aria-label="{$ariaEsc}" class="select col-start-1 row-start-1 w-full appearance-none pr-8" x-model="{$model}"{$changeAttr}>
    {$options}
  </select>
  {$chev}
</div>
HTML;
    }

    /**
     * Render a desktop tabs nav (visible on sm and up) bound to the given Alpine.js model.
     *
     * Uses the trigger page styling as the preferred solution.
     *
     * @param string $model Alpine model name
     * @param array  $items [ ['value' => 'id', 'label' => 'Title'], ... ]
     * @param array  $opts  Optional: ['activeClasses' => string, 'inactiveClasses' => string]
     */
    public static function desktop(string $model, array $items, array $opts = []): string
    {
        $links = self::renderLinks($model, $items, $opts);

        return <<<HTML
<div class="hidden sm:block">
  <nav aria-label="Tabs" class="-mb-px flex space-x-4 border-b border-divider">
    {$links}
  </nav>
  </div>
HTML;
    }

    /**
     * Render only the <nav> with anchors (no responsive wrappers), useful when caller
     * manages its own layout containers (e.g., border + right-side actions).
     */
    public static function desktopNavOnly(string $model, array $items, array $opts = []): string
    {
        $links = self::renderLinks($model, $items, $opts);

        return '<nav aria-label="Tabs" class="-mb-px flex space-x-4">' . $links . '</nav>';
    }

    /**
     * Internal helper to render the <a> links.
     */
    private static function renderLinks(string $model, array $items, array $opts = []): string
    {
        $active   = $opts['activeClasses']   ?? 'inline-flex items-center gap-1.5 border-b-2 px-1 py-4 text-sm font-medium whitespace-nowrap border-brand text-brand';
        $inactive = $opts['inactiveClasses'] ?? 'inline-flex items-center gap-1.5 border-b-2 px-1 py-4 text-sm font-medium whitespace-nowrap border-transparent text-secondary hover:border-emphasis hover:text-primary';
        $compact  = $opts['compact'] ?? false;
        $onClick  = isset($opts['onClick']) ? (string)$opts['onClick'] : '';

        if ($compact) {
            // we handle the gap via margin on the sliding label
            if (!isset($opts['activeClasses'])) {
                $active = preg_replace('/\s+/', ' ', str_replace('gap-1.5', ' ', $active));
            }
            if (!isset($opts['inactiveClasses'])) {
                $inactive = preg_replace('/\s+/', ' ', str_replace('gap-1.5', ' ', $inactive));
            }
        }

        $links = '';
        foreach ($items as $it) {
            if (!is_array($it)) { continue; }
            $val = isset($it['value']) ? (string)$it['value'] : '';
            $lab = isset($it['label']) ? (string)$it['label'] : $val;
            $ico = isset($it['icon'])  ? (string)$it['icon']  : '';
            if ($val === '') { continue; }

            $labEsc = Base::h((string) $lab);
            $valJs  = htmlspecialchars(json_encode($val, JSON_UNESCAPED_UNICODE), ENT_QUOTES);
            $clickExpr = $onClick !== '' ? str_replace('{value}', $valJs, $onClick) : ($model . ' = ' . $valJs);
            $iconHtml  = $ico !== '' ? ('<span class="shrink-0 [&_svg]:size-4">' . $ico . '</span>') : '';
            $xShow     = isset($it['x-show']) ? (' x-show="' . $it['x-show'] . '"') : '';

            if ($compact) {
                $gapClass = ($ico !== '') ? ' ml-1.5' : '';
                $labHtml = '<span class="grid transition-all duration-300 ease-in-out overflow-hidden" '
                         . ':class="' . $model . ' === ' . $valJs . ' ? \'grid-cols-[1fr] opacity-100\' : \'grid-cols-[0fr] opacity-0\'">'
                         . '<span class="overflow-hidden whitespace-nowrap' . $gapClass . '">' . $labEsc . '</span>'
                         . '</span>';
            } else {
                $labHtml = '<span>' . $labEsc . '</span>';
            }

            $links .= <<<HTML
<a href="#"
   @click.prevent="{$clickExpr}"
   {$xShow}
   :aria-current="{$model} === {$valJs} ? 'page' : 'false'"
   :class="{$model} === {$valJs} ? '{$active}' : '{$inactive}'">
  {$iconHtml}
  {$labHtml}
</a>
HTML;
        }

        return $links;
    }
}
