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

class Input extends BaseField {
    public static function render(string $name, string $label, $value = '', array $opts = []): string {
        $validate = $opts['validate'] ?? [];
        $errors = $opts['errors'] ?? [];
        $help = $opts['help'] ?? '';
        $extra = $opts['input_attrs'] ?? '';

        $hasError = !empty($errors);
        $nameEsc = self::h($name);
        $labelEsc = self::h($label);
        $valEsc = self::h((string)$value);

        $vType = strtolower((string)($validate['type'] ?? 'string'));
        // Allow explicit HTML input type override via opts (e.g. date, datetime-local)
        $inputType = (string)($opts['input_type'] ?? '');
        if ($inputType === '') {
            $inputType = 'text';
            if ($vType === 'integer' || $vType === 'number' || $vType === 'float') $inputType = 'number';
            if ($vType === 'boolean') $inputType = 'checkbox';
            if ($vType === 'email') $inputType = 'email';
        }

        // Only include step for numeric inputs
        $stepAttr = '';
        if ($inputType === 'number') {
            $stepAttr = ' step="' . (($vType === 'integer') ? '1' : 'any') . '"';
        }
        $minAttr = isset($validate['min']) && $validate['min'] !== '' ? ' min="' . self::h((string)$validate['min']) . '"' : '';
        $maxAttr = isset($validate['max']) && $validate['max'] !== '' ? ' max="' . self::h((string)$validate['max']) . '"' : '';
        $requiredAttr = !empty($validate['required']) ? ' required' : '';

        $helpHtml = self::helpHtml($help);
        $errorHtml = self::errorsHtml($errors);
        $badge = $opts['label_badge_html'] ?? '';
        $clientErr = self::clientErrorHtml($name);
        $size = $opts['size'] ?? 'md';

        // Build an ID for label association
        $id = (string)($opts['id'] ?? '');
        if ($id === '') {
            $idBase = preg_replace('/[^a-zA-Z0-9_-]+/', '-', $name);
            $idBase = trim($idBase ?? '', '-');
            if ($idBase === '') {
                $idBase = 'input';
            }
            $id = self::h($idBase);
        } else {
            $id = self::h($id);
        }

        // Standardized icon support
        $prefixIconHtml = (string)($opts['prefix_icon_html'] ?? '');
        $suffixIconHtml = (string)($opts['suffix_icon_html'] ?? '');
        $showReset = !empty($opts['show_reset']);
        $isCopyable = !empty($opts['is_copyable']);

        if ($isCopyable) {
            if ($prefixIconHtml === '' && empty($opts['no_copy_icon'])) {
                $prefixIconHtml = self::SVG_KEY;
            }
            if ($suffixIconHtml === '') {
                $xData = '{ copied: false, copy() { const ta = document.getElementById("' . $id . '"); if (!ta) return; const val = ta.value || ""; const done = () => { this.copied = true; ta.blur(); if (window.getSelection) { window.getSelection().removeAllRanges(); } setTimeout(() => this.copied = false, 2000); }; if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(val).then(done).catch(() => { ta.focus(); ta.select(); if (document.execCommand("copy")) done(); }); } else { ta.focus(); ta.select(); if (document.execCommand("copy")) done(); } } }';
                $suffixIconHtml = '<div x-data=\'' . $xData . '\' class="flex items-center">
                    <button type="button" @click="copy()" class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 focus:outline-none" aria-label="Copy to clipboard">
                        <span x-show="!copied">' . self::SVG_COPY . '</span>
                        <span x-show="copied" x-cloak>' . self::SVG_CHECK_CIRCLE . '</span>
                    </button>
                </div>';
            }
        }

        if ($showReset && $suffixIconHtml === '') {
            // Alpine.js reset logic
            // Try to extract x-model from input_attrs if not explicitly provided
            $model = (string)($opts['model'] ?? '');
            if ($model === '') {
                if (preg_match('/\bx-model(?:\.[^=]+)?="([^"]+)"/', $extra, $m)) {
                    $model = $m[1];
                } elseif (preg_match("/\bx-model(?:\.[^=]+)?='([^']+)'/", $extra, $m)) {
                    $model = $m[1];
                }
            }

            $xShow = ($model !== '') ? $model . " !== ''" : "(\$el.parentElement.parentElement.querySelector('input').value || '') !== ''";
            if ($model !== '') {
                $xClick = $model . " = ''; \$nextTick(() => { const input = \$el.parentElement.parentElement.querySelector('input'); input.value = ''; input.dispatchEvent(new Event('search')); input.dispatchEvent(new Event('input')); });";
            } else {
                $xClick = "const input = \$el.parentElement.parentElement.querySelector('input'); input.value = ''; input.dispatchEvent(new Event('search')); input.dispatchEvent(new Event('input'));";
            }

            $suffixIconHtml = '<button type="button" aria-label="Clear"
                x-show="' . self::h($xShow, false) . '" 
                @click="' . self::h($xClick, false) . '" 
                class="flex items-center justify-center text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 focus:outline-none">' . self::SVG_X_MARK . '</button>';
        }

        $hasIcon = ($prefixIconHtml !== '' || $suffixIconHtml !== '');
        $isReadonly = !empty($opts['is_readonly']) || $isCopyable;
        $readonlyAttr = $isReadonly ? ' readonly' : '';


        // Adjust padding if icons are present
        $paddingCls = ' px-3';
        if ($prefixIconHtml !== '') { $paddingCls = ' pl-10 pr-3'; }
        if ($suffixIconHtml !== '') {
            if ($prefixIconHtml !== '') { $paddingCls = ' pl-10 pr-10'; }
            else { $paddingCls = ' pl-3 pr-10'; }
        }

        $inputClass = self::inputClass($hasError, $isReadonly);

        // Optional addons (prefix/suffix) for input group, e.g., 'days'
        $addonPrefixRaw = (string)($opts['addon_prefix'] ?? '');
        $addonSuffixRaw = (string)($opts['addon_suffix'] ?? '');
        $addonPrefix = trim($addonPrefixRaw);
        $addonSuffix = trim($addonSuffixRaw);
        $hasAddon = ($addonPrefix !== '' || $addonSuffix !== '');

        // Group wrapper classes (mirrors Assistant input group styling)
        $groupClass = self::groupClass($hasError, $isReadonly);
        $groupInputClass = 'block min-w-0 grow py-1.5 pr-3 pl-1 text-base text-gray-900 placeholder:text-gray-400 focus:outline-none sm:text-sm/6 dark:bg-transparent dark:text-white dark:placeholder:text-gray-500';

        if ($isCopyable) {
            $inputClass .= ' selection:bg-transparent focus:ring-0 focus:outline-none';
            $groupInputClass .= ' selection:bg-transparent focus:ring-0 focus:outline-none';
        }

        // Adjust padding if not md (since py-1.5 is the default in both inputClass and groupInputClass)
        if ($size === 'xs') {
            $inputClass = str_replace('py-1.5', 'py-0.5', $inputClass);
            $groupInputClass = str_replace('py-1.5', 'py-0.5', $groupInputClass);
        } elseif ($size === 'sm') {
            $inputClass = str_replace('py-1.5', 'py-1', $inputClass);
            $groupInputClass = str_replace('py-1.5', 'py-1', $groupInputClass);
        } elseif ($size === 'lg') {
            $inputClass = str_replace('py-1.5', 'py-2', $inputClass);
            $groupInputClass = str_replace('py-1.5', 'py-2', $groupInputClass);
        }

        $inputClass .= $paddingCls;

        // Custom classes from opts
        $customInputClass = $opts['input_class'] ?? '';
        if ($customInputClass !== '') {
            $inputClass .= ' ' . $customInputClass;
            $groupInputClass .= ' ' . $customInputClass;
        }

        // Build a per-field client validation rule for fallback (data-validate)
        $clientRule = ['type' => $vType];
        if (!empty($validate['required'])) { $clientRule['required'] = true; }
        if (isset($validate['min']) && $validate['min'] !== '') { $clientRule['min'] = is_numeric($validate['min']) ? 0 + $validate['min'] : (string)$validate['min']; }
        if (isset($validate['max']) && $validate['max'] !== '') { $clientRule['max'] = is_numeric($validate['max']) ? 0 + $validate['max'] : (string)$validate['max']; }
        if (!empty($validate['compare'])) {
            $cmp = (array)$validate['compare'];
            $list = (isset($cmp['field']) && is_string($cmp['field'])) ? [$cmp] : array_values($cmp);
            $outCmp = [];
            foreach ($list as $c) {
                if (!is_array($c)) continue;
                $cf = (string)($c['field'] ?? ''); if ($cf === '') continue;
                $op = strtolower((string)($c['op'] ?? 'gte'));
                $item = ['field' => $cf, 'op' => $op];
                $offset = $c['offset'] ?? 0;
                if (array_key_exists('offset', $c)) { $item['offset'] = $offset; }
                if (!empty($c['message'])) {
                    $item['message'] = \Components\Form\Validation::translateCompareMessage((string)$c['message'], $offset, $cf, $opts['fields'] ?? []);
                }
                $outCmp[] = $item;
            }
            if (!empty($outCmp)) { $clientRule['compare'] = $outCmp; }
        }
        $clientRuleAttr = " data-validate='" . htmlspecialchars(json_encode($clientRule), ENT_QUOTES) . "'";

        // Build inner control
        if ($hasAddon) {
            $prefixHtml = '';
            if ($addonPrefix !== '') {
                $prefixEsc = self::h($addonPrefix);
                $prefixHtml = <<<HTML
<div class="shrink-0 text-base text-gray-500 select-none sm:text-sm dark:text-gray-400">{$prefixEsc}</div>
HTML;
            }

            $suffixHtml = '';
            if ($addonSuffix !== '') {
                $suffixEsc = self::h($addonSuffix);
                $suffixHtml = <<<HTML
<div class="shrink-0 text-base text-gray-500 select-none sm:text-sm dark:text-gray-400">{$suffixEsc}</div>
HTML;
            }

            $inputInner = <<<HTML
<div class="{$groupClass}">
    {$prefixHtml}
    <input id="{$id}" name="{$nameEsc}" type="{$inputType}" value="{$valEsc}" class="{$groupInputClass}"{$stepAttr}{$minAttr}{$maxAttr}{$requiredAttr}{$readonlyAttr}{$clientRuleAttr} {$extra}/>
    {$suffixHtml}
</div>
HTML;
        } elseif ($hasIcon) {
            $prefixIcon = '';
            if ($prefixIconHtml !== '') {
                $prefixIcon = <<<HTML
<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3 text-gray-400 [&_svg]:size-4">
    {$prefixIconHtml}
</div>
HTML;
            }
            $suffixIcon = '';
            if ($suffixIconHtml !== '') {
                $suffixIcon = <<<HTML
<div class="absolute inset-y-0 right-0 flex items-center pr-3 [&_svg]:size-4">
    {$suffixIconHtml}
</div>
HTML;
            }

            $inputInner = <<<HTML
<div class="relative">
    {$prefixIcon}
    <input id="{$id}" name="{$nameEsc}" type="{$inputType}" value="{$valEsc}" class="{$inputClass}"{$stepAttr}{$minAttr}{$maxAttr}{$requiredAttr}{$readonlyAttr}{$clientRuleAttr} {$extra}/>
    {$suffixIcon}
</div>
HTML;
        } else {
            $inputInner = <<<HTML
<input id="{$id}" name="{$nameEsc}" type="{$inputType}" value="{$valEsc}" class="{$inputClass}"{$stepAttr}{$minAttr}{$maxAttr}{$requiredAttr}{$readonlyAttr}{$clientRuleAttr} {$extra}/>
HTML;
        }

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

        $inputWrapperClass = $opts['no_label'] ?? false ? '' : 'mt-2';
        return self::renderContainer($labelHtml, $inputInner, $helpHtml, $errorHtml, $clientErr, $opts);
    }
}
