import { h } from 'preact';
import { useState, useEffect } from 'preact/hooks';
import { wsClient } from '../lib/ws';
import { getSignalStore, getMetaStore } from '../lib/stores';
import { logicEngine } from '../lib/logic';
import { useAuth, canWrite } from '../lib/auth';
import type { Widget, SignalMeta } from '../lib/types';

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

export default function Button({ widget, onContextMenu }: Props) {
  const sigRef = widget.signals[0];
  const label      = widget.options['label']      ?? 'Button';
  const sendValue  = widget.options['value']      ?? '1';
  const resetValue = widget.options['resetValue'] ?? '0';
  // mode: oneshot | setReset | persistent
  const mode       = widget.options['mode']       ?? 'oneshot';
  const resetTimeSec = parseFloat(widget.options['resetTime'] ?? '1');
  const confirmOpt = widget.options['confirm'] === 'true';
  // Optional panel-logic sequence fired on click (in addition to any signal write).
  const action = widget.options['action'] ?? '';

  const me = useAuth();
  const [signalVal, setSignalVal] = useState<any>(null);
  const [meta, setMeta] = useState<SignalMeta | null>(null);

  // Subscribe to signal only for persistent mode (to track whether it is active)
  useEffect(() => {
    if (!sigRef || mode !== 'persistent') return;
    return getSignalStore(sigRef).subscribe(sv => setSignalVal(sv.value));
  }, [sigRef?.ds, sigRef?.name, mode]);

  // Track the target signal's writability so the button can be disabled when
  // the user has no permission to write it (real signals only; local panel
  // vars are written client-side and have no backend metadata).
  useEffect(() => {
    if (!sigRef || sigRef.ds === 'local') return;
    return getMetaStore(sigRef).subscribe(setMeta);
  }, [sigRef?.ds, sigRef?.name]);

  // A button that drives a real signal is disabled when the user cannot write
  // it (read-only access, or the signal reports it is not writable). Buttons
  // that only run a logic action — or target a local var — stay enabled.
  const drivesRealSignal = !!sigRef && sigRef.ds !== 'local';
  const writeAllowed = !drivesRealSignal || (canWrite(me.level) && meta?.writable !== false);

  const parsedSend  = isNaN(parseFloat(sendValue))  ? sendValue  : parseFloat(sendValue);
  const parsedReset = isNaN(parseFloat(resetValue)) ? resetValue : parseFloat(resetValue);

  // Persistent mode: button appears pressed while signal value matches sendValue
  const isPressed = mode === 'persistent'
    && signalVal !== null
    && String(signalVal) === String(parsedSend);

  function doWrite(val: any) {
    if (!sigRef) return;
    wsClient.write(sigRef, val);
  }

  function execute() {
    if (sigRef) {
      if (mode === 'setReset') {
        doWrite(parsedSend);
        setTimeout(() => doWrite(parsedReset), Math.max(0, resetTimeSec) * 1000);
      } else if (mode === 'persistent') {
        doWrite(isPressed ? parsedReset : parsedSend);
      } else {
        doWrite(parsedSend);
      }
    }
    if (action) logicEngine.runAction(action);
  }

  function handleClick() {
    // A button may drive a signal, a logic sequence, or both.
    if (!sigRef && !action) return;
    if (!writeAllowed) return;
    if (confirmOpt) {
      if (window.confirm(`Send ${label}?`)) execute();
    } else {
      execute();
    }
  }

  return (
    <div
      class="button-widget"
      style={`left:${widget.x}px;top:${widget.y}px;width:${widget.w}px;height:${widget.h}px;`}
      onContextMenu={onContextMenu}
    >
      <button class={`btn${isPressed ? ' btn-pressed' : ''}`} onClick={handleClick}
        disabled={!writeAllowed}
        title={writeAllowed ? '' : 'You do not have permission to write this signal'}>
        {label}
        {mode === 'setReset' && (
          <span class="btn-mode-hint">{resetTimeSec}s</span>
        )}
      </button>
    </div>
  );
}
