import { useEffect, useRef, useState } from 'react';
import { CheckBox } from '@/Components/Proto/UI/CheckBox';
import { cn } from '@/Proto/utils';
import { ChevronDown, Search, X } from 'lucide-react';

// MultiSelect — every selected option is shown as a removable chip in the trigger, so the
// full selection is visible (and deselectable) without reopening the dropdown.
//
// Supports two option shapes:
//   - strings (filter pills): value is an array of strings.
//   - objects { id, name } (FK pickers): value is an array of ids.
// `value` stays a flat array of keys (string|id) in both modes.
const optKey = (o) => (o !== null && typeof o === 'object' ? o.id : o);
const optLabel = (o) => (o !== null && typeof o === 'object' ? o.name : o);

// `invalid` mirrors FloatingField / SearchableSelect: red border + red resting label + a caption,
// and `data-invalid="true"` on the wrapper so useJumpToFirstInvalid() can find it in DOM order.
// Default false, so existing call-sites are unaffected.
export function MultiSelect({ label, placeholder = 'All', options, value, onChange, searchPlaceholder = 'Search…', invalid = false, invalidText = 'Required', }) {
    const [open, setOpen] = useState(false);
    const [query, setQuery] = useState('');
    const ref = useRef(null);
    useEffect(() => {
        const handler = (e) => {
            if (ref.current && !ref.current.contains(e.target))
                setOpen(false);
        };
        if (open)
            document.addEventListener('mousedown', handler);
        return () => document.removeEventListener('mousedown', handler);
    }, [open]);
    useEffect(() => {
        const onEsc = (e) => { if (e.key === 'Escape')
            setOpen(false); };
        if (open)
            document.addEventListener('keydown', onEsc);
        return () => document.removeEventListener('keydown', onEsc);
    }, [open]);
    const toggle = (key) => {
        onChange(value.includes(key) ? value.filter((v) => v !== key) : [...value, key]);
    };
    const filtered = options.filter((o) => !query || String(optLabel(o)).toLowerCase().includes(query.toLowerCase()));
    const hasValue = value.length > 0;
    const selectedOptions = options.filter((o) => value.includes(optKey(o)));
    return (<div ref={ref} className="relative" data-invalid={invalid ? 'true' : undefined}>
      {/* Trigger — every selected option is shown as a removable chip, so the user sees
          the full selection (and can deselect) without reopening the dropdown. */}
      <div role="button" tabIndex={0} aria-haspopup="listbox" aria-expanded={open}
        onClick={() => setOpen((o) => !o)}
        onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setOpen((o) => !o); } }}
        className={cn('relative flex min-h-11 w-full cursor-pointer flex-wrap items-center gap-1.5 rounded-lg border bg-card px-2 py-1.5 pr-8 text-[11px] transition-colors', open ? 'border-primary' : 'border-input hover:border-primary', invalid && !open && 'border-danger')}>
        {!hasValue && <span className="px-1 font-medium text-muted-foreground">{placeholder}</span>}
        {selectedOptions.map((o) => (
          <span key={optKey(o)} className="inline-flex items-center gap-1 rounded-full bg-secondary py-0.5 pl-2 pr-1 text-[10px] font-semibold text-card-foreground">
            {optLabel(o)}
            <button type="button" aria-label={`Remove ${optLabel(o)}`}
              onClick={(e) => { e.stopPropagation(); toggle(optKey(o)); }}
              className="grid size-3.5 place-items-center rounded-full text-muted-foreground transition-colors hover:bg-destructive/15 hover:text-destructive">
              <X className="size-2.5" aria-hidden="true" />
            </button>
          </span>
        ))}
        <ChevronDown aria-hidden="true" className={cn('pointer-events-none absolute right-3 top-3.5 size-3.5 text-muted-foreground transition-transform', open && 'rotate-180')}/>
      </div>

      {/* Floating label (sits on top border) */}
      <span className={cn('pointer-events-none absolute left-2 top-0 -translate-y-1/2 bg-card px-1 text-[10px] font-semibold leading-none', open ? 'text-primary' : invalid ? 'text-danger-text' : 'text-muted-foreground')}>
        {label}
      </span>
      {invalid && <p className="mt-1 text-[11px] font-semibold text-danger-text">{invalidText}</p>}

      {/* Popup */}
      {open && (<div className="absolute left-0 right-0 top-full z-30 mt-1 flex max-h-80 flex-col overflow-hidden rounded-lg border border-border bg-card shadow-modal">
          <label className="flex items-center gap-2 border-b border-border px-3 py-2.5 text-muted-foreground">
            <Search aria-hidden="true" className="size-3.5 shrink-0"/>
            <input type="search" autoFocus value={query} onChange={(e) => setQuery(e.target.value)} placeholder={searchPlaceholder} className="h-7 flex-1 bg-transparent text-[11px] text-card-foreground placeholder:text-muted-foreground focus:outline-none"/>
          </label>
          <ul role="listbox" className="flex-1 list-none overflow-y-auto py-1.5">
            {filtered.length === 0 ? (<li className="px-3.5 py-3.5 text-center text-[11px] italic text-muted-foreground">No options found</li>) : (filtered.map((opt) => {
                const key = optKey(opt);
                const selected = value.includes(key);
                return (<li key={key}>
                    {/* Shared CheckBox, not a native input tinted with accent-primary: that one
                        is the BROWSER's box (its own size, radius, focus ring and check glyph per
                        OS) and was the last control here still ignoring the app's own checkbox. */}
                    <label className="flex cursor-pointer items-center gap-2.5 px-3.5 py-2 text-[11px] text-foreground transition-colors hover:bg-secondary/40">
                      <CheckBox size="sm" checked={selected} onChange={() => toggle(key)} ariaLabel={optLabel(opt)} />
                      <span className="leading-tight">{optLabel(opt)}</span>
                    </label>
                  </li>);
            }))}
          </ul>
          {value.length > 0 && (<div className="border-t border-border px-3 py-2">
              <button type="button" onClick={() => onChange([])} className="text-[10px] font-semibold text-primary hover:underline">
                Clear selection ({value.length})
              </button>
            </div>)}
        </div>)}
    </div>);
}
