import { h } from 'preact';
import { useState, useEffect } from 'preact/hooks';
import { wsClient } from '../lib/ws';
import { getSignalStore } from '../lib/stores';
import type { Widget, SignalValue } from '../lib/types';

interface InstanceMeta { id: string; name: string; setId?: string; }

interface Props { widget: Widget; onContextMenu?: (e: MouseEvent) => void; }

// A combo that lists the config instances of a chosen set and writes the
// selected instance id (a string) to a panel-local variable. The output var can
// then drive the apply/read/write config logic nodes (set to "From variable"),
// letting an operator pick which configuration the flow operates on at run time.
export default function ConfigSelect({ widget, onContextMenu }: Props) {
  const setId = widget.options['set'] || '';
  const output = widget.options['output'] || '';
  const label = widget.options['label'] || 'Config';
  // Optional comma-separated allow-list of instance ids; empty shows them all.
  const subset = (widget.options['instances'] || '')
    .split(',').map(s => s.trim()).filter(Boolean);

  const [instances, setInstances] = useState<InstanceMeta[]>([]);
  const [selected, setSelected] = useState('');

  // Mirror the output var so external writers (e.g. a create-config node) keep
  // the combo in sync.
  useEffect(() => {
    if (!output) return;
    const unsub = getSignalStore({ ds: 'local', name: output }).subscribe((v: SignalValue) => {
      const id = v.value == null ? '' : String(v.value);
      setSelected(prev => (id && id !== prev ? id : prev));
    });
    return unsub;
  }, [output]);

  useEffect(() => {
    let cancelled = false;
    fetch('/api/v1/config/instances')
      .then(r => r.ok ? r.json() : [])
      .then((list: InstanceMeta[]) => {
        if (cancelled) return;
        let filtered = (list ?? []).filter(ci => !setId || ci.setId === setId);
        if (subset.length > 0) filtered = filtered.filter(ci => subset.includes(ci.id));
        setInstances(filtered);
        // Default the output to the first instance when nothing is chosen yet.
        setSelected(prev => {
          if (prev && filtered.some(ci => ci.id === prev)) return prev;
          const first = filtered[0]?.id ?? '';
          if (first && output) wsClient.write({ ds: 'local', name: output }, first);
          return first;
        });
      })
      .catch(() => {});
    return () => { cancelled = true; };
  }, [setId, widget.options['instances']]);

  function onChange(id: string) {
    setSelected(id);
    if (output) wsClient.write({ ds: 'local', name: output }, id);
  }

  return (
    <div
      class="configselect"
      style={`left:${widget.x}px;top:${widget.y}px;width:${widget.w}px;height:${widget.h}px;`}
      onContextMenu={onContextMenu}
    >
      <span class="cs-label">{label}:</span>
      <select
        class="cs-select"
        value={selected}
        onChange={(e: Event) => onChange((e.target as HTMLSelectElement).value)}
      >
        {instances.length === 0 && <option value="">no instances</option>}
        {instances.map(ci => <option key={ci.id} value={ci.id}>{ci.name}</option>)}
      </select>
    </div>
  );
}
