import { h } from 'preact';
import { useState, useEffect } from 'preact/hooks';

interface NodeParam {
  label: string;
  key: string;
  type: 'number' | 'text';
  default: string;
}

const NODE_TYPES: Array<{ type: string; label: string; params: NodeParam[] }> = [
  { type: 'gain',           label: 'Gain',           params: [{ label: 'Factor',        key: 'gain',   type: 'number', default: '1' }] },
  { type: 'offset',         label: 'Offset',         params: [{ label: 'Offset',        key: 'offset', type: 'number', default: '0' }] },
  { type: 'moving_average', label: 'Moving Average', params: [{ label: 'Window (n)',    key: 'window', type: 'number', default: '10' }] },
  { type: 'rms',            label: 'RMS',            params: [{ label: 'Window (n)',    key: 'window', type: 'number', default: '10' }] },
  { type: 'derivative',     label: 'Derivative',     params: [] },
  { type: 'clamp',          label: 'Clamp',          params: [{ label: 'Min', key: 'min', type: 'number', default: '0' }, { label: 'Max', key: 'max', type: 'number', default: '100' }] },
  { type: 'expr',           label: 'Formula',        params: [{ label: 'Expression (a=input)', key: 'expr', type: 'text', default: 'a * 1.0' }] },
  { type: 'lua',            label: 'Lua Script',     params: [{ label: 'Script (a=input)',      key: 'script', type: 'text', default: 'return a' }] },
];

interface PipelineNode {
  type: string;
  params: Record<string, any>;
}

interface SignalDef {
  name: string;
  ds: string;
  signal: string;
  pipeline: PipelineNode[];
  meta: {
    unit?: string;
    description?: string;
    displayLow?: number;
    displayHigh?: number;
  };
}

interface Props {
  name: string;
  onClose: () => void;
  onSaved: () => void;
}

export default function SyntheticEditor({ name, onClose, onSaved }: Props) {
  const [def, setDef] = useState<SignalDef | null>(null);
  const [pipeline, setPipeline] = useState<PipelineNode[]>([]);
  const [addType, setAddType] = useState('gain');
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState('');

  useEffect(() => {
    fetch(`/api/v1/synthetic/${encodeURIComponent(name)}`)
      .then(r => r.ok ? r.json() : Promise.reject(r.statusText))
      .then((d: SignalDef) => {
        setDef(d);
        setPipeline(d.pipeline ?? []);
      })
      .catch(e => setError(String(e)))
      .finally(() => setLoading(false));
  }, [name]);

  function nodeLabel(type: string): string {
    return NODE_TYPES.find(n => n.type === type)?.label ?? type;
  }

  function nodeParamDefs(type: string): NodeParam[] {
    return NODE_TYPES.find(n => n.type === type)?.params ?? [];
  }

  function setNodeParam(idx: number, key: string, val: string) {
    setPipeline(p => p.map((node, i) => {
      if (i !== idx) return node;
      const paramDef = nodeParamDefs(node.type).find(pd => pd.key === key);
      const typed: any = paramDef?.type === 'number' ? parseFloat(val) : val;
      return { ...node, params: { ...node.params, [key]: typed } };
    }));
  }

  function removeNode(idx: number) {
    setPipeline(p => p.filter((_, i) => i !== idx));
  }

  function moveNode(idx: number, dir: -1 | 1) {
    setPipeline(p => {
      const next = [...p];
      const target = idx + dir;
      if (target < 0 || target >= next.length) return next;
      [next[idx], next[target]] = [next[target], next[idx]];
      return next;
    });
  }

  function addNode() {
    const nodeDef = NODE_TYPES.find(n => n.type === addType)!;
    const params: Record<string, any> = {};
    for (const p of nodeDef.params) {
      params[p.key] = p.type === 'number' ? parseFloat(p.default) : p.default;
    }
    setPipeline(p => [...p, { type: addType, params }]);
  }

  async function handleSave() {
    if (!def) return;
    setSaving(true);
    setError('');
    try {
      const body = { ...def, pipeline };
      const res = await fetch(`/api/v1/synthetic/${encodeURIComponent(name)}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body),
      });
      if (!res.ok) {
        const j = await res.json().catch(() => ({ error: res.statusText }));
        throw new Error(j.error ?? res.statusText);
      }
      onSaved();
      onClose();
    } catch (err) {
      setError(err instanceof Error ? err.message : String(err));
    } finally {
      setSaving(false);
    }
  }

  return (
    <div class="wizard-backdrop" onClick={onClose}>
      <div class="wizard" onClick={(e) => e.stopPropagation()} style="max-width:560px;">
        <div class="wizard-header">
          <span>Edit Pipeline — {name}</span>
          <button class="icon-btn" onClick={onClose}>✕</button>
        </div>

        <div class="wizard-body">
          {error && <p class="wizard-error">{error}</p>}
          {loading ? (
            <p class="hint">Loading…</p>
          ) : (
            <div>
              <div class="wizard-section-title">Pipeline nodes</div>
              {pipeline.length === 0 && (
                <p class="hint" style="padding:0.5rem 0;">No processing nodes — input passes through unchanged.</p>
              )}
              {pipeline.map((node, idx) => {
                const paramDefs = nodeParamDefs(node.type);
                return (
                  <div key={idx} class="synth-pipeline-node">
                    <div class="synth-node-header">
                      <span class="synth-node-index">{idx + 1}</span>
                      <span class="synth-node-label">{nodeLabel(node.type)}</span>
                      <div class="synth-node-actions">
                        <button class="icon-btn" title="Move up" disabled={idx === 0} onClick={() => moveNode(idx, -1)}>↑</button>
                        <button class="icon-btn" title="Move down" disabled={idx === pipeline.length - 1} onClick={() => moveNode(idx, 1)}>↓</button>
                        <button class="icon-btn" title="Remove node" onClick={() => removeNode(idx)}>✕</button>
                      </div>
                    </div>
                    {paramDefs.map(pd => (
                      <div key={pd.key} class="wizard-field wizard-field-inline">
                        <label>{pd.label}</label>
                        <input
                          class="prop-input"
                          type={pd.type === 'number' ? 'number' : 'text'}
                          value={node.params[pd.key] ?? pd.default}
                          onInput={(e) => setNodeParam(idx, pd.key, (e.target as HTMLInputElement).value)}
                        />
                      </div>
                    ))}
                  </div>
                );
              })}

              <div class="synth-add-node-row">
                <select class="prop-select" value={addType} onChange={(e) => setAddType((e.target as HTMLSelectElement).value)}>
                  {NODE_TYPES.map(n => <option key={n.type} value={n.type}>{n.label}</option>)}
                </select>
                <button class="toolbar-btn" onClick={addNode}>+ Add node</button>
              </div>
            </div>
          )}
        </div>

        <div class="wizard-footer">
          <button class="toolbar-btn" onClick={onClose}>Cancel</button>
          <button class="toolbar-btn toolbar-btn-primary" onClick={handleSave} disabled={saving || loading}>
            {saving ? 'Saving…' : 'Save Pipeline'}
          </button>
        </div>
      </div>
    </div>
  );
}
