<?php
namespace PpPhp\Plugins;
use PpPhp\Core\EditPlugin;
use PpPhp\Core\Designer\FieldControl\LookupOptions;

/**
 * Dropdown edit control — a native <select> styled as a modern button
 * dropdown (variant / color / size / shape). Options from a manual list
 * (plain or value:Label) or a database-table lookup with WHERE condition.
 * Native select = reliable keyboard, mobile and form submission.
 */
class Dropdown implements EditPlugin
{
    private const COLORS = ['primary', 'info', 'success', 'warning', 'danger', 'secondary', 'dark'];

    public static function id(): string { return 'Dropdown'; }
    public static function label(): string { return 'Dropdown'; }
    public static function version(): string { return '1.0.0'; }
    public static function description(): string { return 'A select dropdown with static or table-driven options.'; }

    public static function render(string $fieldName, mixed $value, array $settings): string
    {
        $variant = (string) ($settings['variant'] ?? 'solid');
        $color = (string) ($settings['color'] ?? 'primary'); if (!in_array($color, self::COLORS, true)) $color = 'primary';
        $size = (string) ($settings['size'] ?? 'md'); if (!in_array($size, ['sm','md','lg'], true)) $size = 'md';
        $rounded = ($settings['shape'] ?? 'default') === 'rounded';
        $block = in_array(strtolower((string) ($settings['block'] ?? '')), ['1', 'yes', 'true', 'on'], true);
        $disabled = ($settings['state'] ?? '') === 'disabled';
        $multiple = in_array(strtolower((string) ($settings['multiple'] ?? '')), ['1', 'yes', 'true', 'on'], true);
        $placeholder = (string) ($settings['placeholder'] ?? '— Select —');

        $cls = 'pp-b2 pp-dd pp-bc-' . $color . ' pp-bz-' . $size
            . ($variant === 'outline' ? ' is-outline' : ($variant === 'light' ? ' is-light' : ''))
            . ($rounded ? ' is-rounded' : '') . ($block ? ' is-block' : '') . ($disabled ? ' is-disabled' : '');

        // Multiple selection — a tag/token multi-select: chips for chosen values,
        // a dropdown of the remaining options, type-to-filter. Posts fieldName[]
        // which the generated save flow stores comma-separated. Progressive
        // enhancement: a plain native multi-select still works without JS.
        if ($multiple) {
            $selected = array_values(array_filter(array_map('trim', explode(',', (string) $value)), 'strlen'));
            $native = '<select name="' . $fieldName . '[]" id="field_' . $fieldName . '" class="pp-ddms-native" multiple' . ($disabled ? ' disabled' : '') . '>';
            $known = [];
            foreach (LookupOptions::resolve($settings) as $val => $label) {
                $known[] = (string) $val;
                $s = in_array((string) $val, $selected, true) ? ' selected' : '';
                $native .= '<option value="' . htmlspecialchars((string) $val) . '"' . $s . '>' . htmlspecialchars((string) $label) . '</option>';
            }
            foreach (array_diff($selected, $known) as $miss) {   // keep off-list values
                $safe = htmlspecialchars((string) $miss);
                $native .= '<option value="' . $safe . '" selected>' . $safe . '</option>';
            }
            $native .= '</select>';
            $ph = htmlspecialchars($placeholder !== '' ? $placeholder : 'Select…');
            return '<div class="pp-ddms' . ($block ? ' is-block' : '') . ($disabled ? ' is-disabled' : '') . '">'
                . $native
                . '<div class="pp-ddms-control" style="display:none"><span class="pp-ddms-tags"></span>'
                . '<input class="pp-ddms-input" type="text" placeholder="' . $ph . '" data-ph="' . $ph . '"' . ($disabled ? ' disabled' : '') . ' autocomplete="off">'
                . '<i class="bi bi-chevron-down pp-ddms-caret"></i></div>'
                . '<div class="pp-ddms-panel" hidden></div>'
                . '</div>' . self::multiSelectAssets();
        }

        $opts = '<option value="">' . htmlspecialchars($placeholder) . '</option>';
        foreach (LookupOptions::resolve($settings) as $val => $label) {
            $sel = ((string) $value === (string) $val) ? ' selected' : '';
            $opts .= '<option value="' . htmlspecialchars((string) $val) . '"' . $sel . '>' . htmlspecialchars((string) $label) . '</option>';
        }

        return '<div class="' . $cls . '"><select name="' . $fieldName . '" id="field_' . $fieldName . '"'
            . ($disabled ? ' disabled' : '') . '>' . $opts . '</select><i class="bi bi-chevron-down"></i></div>';
    }

    /**
     * One-time (guarded) chip/token multi-select enhancement — styles + JS.
     * Chosen values render as removable chips; the dropdown lists only the
     * remaining options and supports type-to-filter and keyboard navigation.
     * The underlying native <select multiple> stays the form's source of truth.
     */
    private static function multiSelectAssets(): string
    {
        return <<<'HTML'
<script>(function(){
if(window.__ppDdms)return; window.__ppDdms=1;
var css=".pp-ddms{position:relative;width:100%;}"
+".pp-ddms.is-block{width:100%;}"
+".pp-ddms-control{display:flex;flex-wrap:wrap;align-items:center;gap:.3rem;min-height:2.5rem;padding:.3rem .5rem;border:1px solid var(--pp-border,#cbd5e1);border-radius:.55rem;background:var(--pp-surface,#fff);cursor:text;transition:border-color .12s,box-shadow .12s;}"
+".pp-ddms-control.is-open,.pp-ddms-control:focus-within{border-color:var(--pp-primary,#2563eb);box-shadow:0 0 0 3px color-mix(in srgb,var(--pp-primary,#2563eb) 16%,transparent);}"
+".pp-ddms.is-disabled .pp-ddms-control{background:var(--pp-surface-soft,#f1f5f9);cursor:not-allowed;opacity:.7;}"
+".pp-ddms-tag{display:inline-flex;align-items:center;gap:.3rem;background:var(--pp-primary-soft,#eff6ff);color:var(--pp-primary,#1d4ed8);border:1px solid color-mix(in srgb,var(--pp-primary,#2563eb) 26%,transparent);border-radius:999px;padding:.12rem .3rem .12rem .6rem;font-size:.82rem;font-weight:600;line-height:1.4;}"
+".pp-ddms-tag b{cursor:pointer;font-weight:700;padding:0 .18rem;opacity:.65;font-size:.95rem;}"
+".pp-ddms-tag b:hover{opacity:1;}"
+".pp-ddms-input{flex:1 1 70px;min-width:70px;border:0;outline:0;background:transparent;font-size:.9rem;padding:.25rem .1rem;color:var(--pp-text,#0f172a);}"
+".pp-ddms-caret{margin-left:auto;color:var(--pp-muted,#64748b);font-size:.72rem;padding-left:.3rem;pointer-events:none;}"
+".pp-ddms-panel{position:absolute;z-index:1050;left:0;right:0;top:100%;margin-top:.3rem;max-height:240px;overflow-y:auto;background:var(--pp-surface,#fff);border:1px solid var(--pp-border,#e2e8f0);border-radius:.55rem;box-shadow:0 12px 34px rgba(2,6,23,.16);}"
+".pp-ddms-opt{padding:.5rem .7rem;cursor:pointer;font-size:.9rem;color:var(--pp-text,#0f172a);}"
+".pp-ddms-opt.is-active,.pp-ddms-opt:hover{background:var(--pp-primary-soft,#eff6ff);color:var(--pp-primary,#1d4ed8);}"
+".pp-ddms-empty{padding:.55rem .7rem;color:var(--pp-muted,#94a3b8);font-size:.85rem;}";
var st=document.createElement('style');st.textContent=css;document.head.appendChild(st);
function esc(s){var d=document.createElement('div');d.textContent=s;return d.innerHTML;}
function sel(w){return w.querySelector('select');}
function chosen(s){return [].filter.call(s.options,function(o){return o.selected&&o.value!=='';}).length;}
function renderTags(w){var s=sel(w),c=w.querySelector('.pp-ddms-tags'),inp=w.querySelector('.pp-ddms-input');
 c.innerHTML='';
 [].forEach.call(s.options,function(o,i){if(o.selected&&o.value!==''){var t=document.createElement('span');t.className='pp-ddms-tag';
  var lb=document.createElement('span');lb.textContent=o.text;t.appendChild(lb);
  var x=document.createElement('b');x.textContent='×';x.setAttribute('data-rm',i);t.appendChild(x);c.appendChild(t);}});
 inp.placeholder=chosen(s)?'':(inp.getAttribute('data-ph')||'');}
function renderPanel(w,f){var s=sel(w),p=w.querySelector('.pp-ddms-panel');f=(f||'').toLowerCase();
 var av=[];[].forEach.call(s.options,function(o,i){if(o.value!==''&&!o.selected&&(!f||o.text.toLowerCase().indexOf(f)>=0))av.push({i:i,t:o.text});});
 if(!av.length){p.innerHTML='<div class="pp-ddms-empty">'+(f?'No matches':'All selected')+'</div>';}
 else{p.innerHTML=av.map(function(a,j){return '<div class="pp-ddms-opt'+(j===0?' is-active':'')+'" data-add="'+a.i+'">'+esc(a.t)+'</div>';}).join('');}
 p.hidden=false;w.querySelector('.pp-ddms-control').classList.add('is-open');}
function close(w){w.querySelector('.pp-ddms-panel').hidden=true;w.querySelector('.pp-ddms-control').classList.remove('is-open');}
function fire(s){s.dispatchEvent(new Event('change',{bubbles:true}));}
document.addEventListener('click',function(e){
 [].forEach.call(document.querySelectorAll('.pp-ddms'),function(w){if(!w.contains(e.target))close(w);});
 var w=e.target.closest?e.target.closest('.pp-ddms'):null;if(!w||w.classList.contains('is-disabled'))return;
 var s=sel(w);
 var rm=e.target.closest('[data-rm]');
 if(rm){s.options[+rm.getAttribute('data-rm')].selected=false;renderTags(w);var inp=w.querySelector('.pp-ddms-input');renderPanel(w,inp.value);fire(s);return;}
 var add=e.target.closest('[data-add]');
 if(add){s.options[+add.getAttribute('data-add')].selected=true;var inp=w.querySelector('.pp-ddms-input');inp.value='';renderTags(w);renderPanel(w,'');inp.focus();fire(s);return;}
 if(e.target.closest('.pp-ddms-control')){var inp=w.querySelector('.pp-ddms-input');renderPanel(w,inp.value);inp.focus();}
});
document.addEventListener('input',function(e){var inp=e.target.closest?e.target.closest('.pp-ddms-input'):null;if(!inp)return;renderPanel(inp.closest('.pp-ddms'),inp.value);});
document.addEventListener('keydown',function(e){var inp=e.target.closest?e.target.closest('.pp-ddms-input'):null;if(!inp)return;var w=inp.closest('.pp-ddms'),p=w.querySelector('.pp-ddms-panel');
 if(e.key==='Backspace'&&inp.value===''){var s=sel(w),last=null;[].forEach.call(s.options,function(o,i){if(o.selected&&o.value!=='')last=i;});if(last!==null){s.options[last].selected=false;renderTags(w);renderPanel(w,'');fire(s);}return;}
 if(p.hidden&&(e.key==='ArrowDown'||e.key==='Enter')){renderPanel(w,inp.value);e.preventDefault();return;}
 var items=[].slice.call(p.querySelectorAll('.pp-ddms-opt'));if(!items.length)return;
 var ai=items.findIndex(function(x){return x.classList.contains('is-active');});
 if(e.key==='ArrowDown'){e.preventDefault();if(ai>=0)items[ai].classList.remove('is-active');items[Math.min(ai+1,items.length-1)].classList.add('is-active');items[Math.min(ai+1,items.length-1)].scrollIntoView({block:'nearest'});}
 else if(e.key==='ArrowUp'){e.preventDefault();if(ai>=0)items[ai].classList.remove('is-active');items[Math.max(ai-1,0)].classList.add('is-active');items[Math.max(ai-1,0)].scrollIntoView({block:'nearest'});}
 else if(e.key==='Enter'){e.preventDefault();var pick=ai>=0?items[ai]:items[0];if(pick){var s=sel(w);s.options[+pick.getAttribute('data-add')].selected=true;inp.value='';renderTags(w);renderPanel(w,'');fire(s);}}
 else if(e.key==='Escape'){close(w);}
});
window.__ppDdmsInit=function(){[].forEach.call(document.querySelectorAll('.pp-ddms'),function(w){var s=sel(w);if(w.getAttribute('data-on'))return;w.setAttribute('data-on','1');s.style.display='none';w.querySelector('.pp-ddms-control').style.display='flex';renderTags(w);});};
if(document.readyState!=='loading')window.__ppDdmsInit();else document.addEventListener('DOMContentLoaded',window.__ppDdmsInit);
})();</script>
HTML;
    }

    public static function settingsSchema(): array
    {
        return array_merge([
            ['key' => 'variant', 'label' => 'Variant', 'type' => 'select', 'options' => ['solid', 'outline', 'light'], 'default' => 'solid'],
            ['key' => 'color', 'label' => 'Color', 'type' => 'select', 'options' => self::COLORS, 'default' => 'primary'],
            ['key' => 'size', 'label' => 'Size', 'type' => 'select', 'options' => ['sm', 'md', 'lg'], 'default' => 'md'],
            ['key' => 'shape', 'label' => 'Shape', 'type' => 'select', 'options' => ['default', 'rounded'], 'default' => 'default'],
            ['key' => 'block', 'label' => 'Full width', 'type' => 'bool', 'default' => 'no'],
            ['key' => 'placeholder', 'label' => 'Placeholder', 'type' => 'text', 'default' => '— Select —'],
            ['key' => 'state', 'label' => 'State', 'type' => 'select', 'options' => ['normal', 'disabled'], 'default' => 'normal'],
            ['key' => 'multiple', 'label' => 'Multiple selection', 'type' => 'bool', 'default' => 'no', 'hint' => 'Let users pick several values (stored comma-separated).'],
        ], LookupOptions::schema());
    }

    public static function assets(): array { return ['js' => [], 'css' => []]; }
}
