import { h } from 'preact';
import { useState, useEffect } from 'preact/hooks';
import { initLocalState } from './lib/localstate';
import { logicEngine } from './lib/logic';
import type { Interface, Widget, SignalRef } from './lib/types';
import TextView from './widgets/TextView';
import TextLabel from './widgets/TextLabel';
import Gauge from './widgets/Gauge';
import BarH from './widgets/BarH';
import BarV from './widgets/BarV';
import Led from './widgets/Led';
import MultiLed from './widgets/MultiLed';
import SetValue from './widgets/SetValue';
import Button from './widgets/Button';
import PlotWidget from './widgets/PlotWidget';
import ImageWidget from './widgets/ImageWidget';
import LinkWidget from './widgets/LinkWidget';
import ContextMenu from './ContextMenu';
import InfoPanel from './InfoPanel';
import SplitLayout from './SplitLayout';
import LogicDialogs from './LogicDialogs';

const COMPONENTS: Record<string, any> = {
  textview:  TextView,
  textlabel: TextLabel,
  gauge:     Gauge,
  barh:      BarH,
  barv:      BarV,
  led:       Led,
  multiled:  MultiLed,
  setvalue:  SetValue,
  button:    Button,
  plot:      PlotWidget,
  image:     ImageWidget,
  link:      LinkWidget,
};

interface CtxState {
  visible: boolean;
  x: number;
  y: number;
  signal: SignalRef | null;
}

interface Props {
  iface: Interface | null;
  onNavigate?: (interfaceId: string) => void;
  timeRange?: { start: string; end: string } | null;
}

export default function Canvas({ iface, onNavigate, timeRange }: Props) {
  const [ctxMenu, setCtxMenu] = useState<CtxState>({
    visible: false, x: 0, y: 0, signal: null,
  });
  const [infoSignal, setInfoSignal] = useState<SignalRef | null>(null);

  // Instantiate this panel's local state variables from their initial values.
  useEffect(() => {
    initLocalState(iface?.statevars);
  }, [iface?.id, iface?.statevars]);

  // Activate panel logic for the live view; tear it down on unmount/panel switch.
  useEffect(() => {
    logicEngine.load(iface?.logic);
    return () => logicEngine.clear();
  }, [iface?.id, iface?.logic]);

  function onCtxMenu(e: MouseEvent, widget: Widget) {
    e.preventDefault();
    e.stopPropagation();
    setCtxMenu({ visible: true, x: e.clientX, y: e.clientY, signal: widget.signals[0] ?? null });
  }

  function closeCtxMenu() {
    setCtxMenu(c => ({ ...c, visible: false }));
  }

  function handleInfo() {
    if (ctxMenu.signal) setInfoSignal(ctxMenu.signal);
  }

  if (!iface) {
    return (
      <div class="canvas-container">
        <div class="placeholder">
          <p>Select an interface from the left panel, or import one.</p>
        </div>
      </div>
    );
  }

  // Plot panel: plots fill the viewport arranged in a recursive split layout.
  if (iface.kind === 'plot' && iface.layout) {
    const byId = new Map(iface.widgets.map(w => [w.id, w]));
    return (
      <div class="canvas-container">
        <div class="plot-panel-view">
          <SplitLayout
            layout={iface.layout}
            renderLeaf={(wid) => {
              const widget = byId.get(wid);
              if (!widget) return <div class="plot-pane-empty">missing plot</div>;
              return (
                <PlotWidget
                  widget={widget}
                  onContextMenu={(e: MouseEvent) => onCtxMenu(e, widget)}
                  timeRange={timeRange}
                />
              );
            }}
          />
        </div>

        <ContextMenu
          {...ctxMenu}
          onClose={closeCtxMenu}
          onInfo={handleInfo}
        />

        {infoSignal && (
          <InfoPanel signal={infoSignal} onClose={() => setInfoSignal(null)} />
        )}

        <LogicDialogs />
      </div>
    );
  }

  return (
    <div class="canvas-container">
      <div class="canvas-area" style={`width:${iface.w}px;height:${iface.h}px;`}>
        {iface.widgets.map(widget => {
          const Comp = COMPONENTS[widget.type];
          return Comp
            ? <Comp
                key={widget.id}
                widget={widget}
                onContextMenu={(e: MouseEvent) => onCtxMenu(e, widget)}
                onNavigate={onNavigate}
                timeRange={timeRange}
              />
            : (
              <div
                key={widget.id}
                class="unknown-widget"
                style={`left:${widget.x}px;top:${widget.y}px;width:${widget.w}px;height:${widget.h}px;`}
                title={`Unknown widget type: ${widget.type}`}
                onContextMenu={(e: MouseEvent) => onCtxMenu(e, widget)}
              >
                <span class="unknown-label">{widget.type}</span>
              </div>
            );
        })}
      </div>

      <ContextMenu
        {...ctxMenu}
        onClose={closeCtxMenu}
        onInfo={handleInfo}
      />

      {infoSignal && (
        <InfoPanel signal={infoSignal} onClose={() => setInfoSignal(null)} />
      )}

      <LogicDialogs />
    </div>
  );
}
