// Admin / edit-mode primitives
// Exposes:
//   window.useCMS()                — subscribes to CMS, returns [state, setKey, update]
//   window.useEditMode()           — [editing, setEditing]
//   window.EditableText            — contentEditable inline text bound to CMS
//   window.EditableUrl             — text + url pair editor (modal popover)
//   window.AdminBar                — floating top toolbar (when admin)
//   window.AdminAddButton          — "+ add" tile
//   window.AdminItemControls       — hover overlay (delete / move)

const { useState, useEffect, useRef, useCallback } = React;

// ============ HOOKS ============
window.useCMS = function () {
  const [state, setState] = useState(window.CMS.get());
  useEffect(() => {
    const unsub = window.CMS.subscribe((s) => setState({ ...s }));
    return unsub;
  }, []);
  const setKey = useCallback((k, v) => window.CMS.set(k, v), []);
  const update = useCallback((fn) => window.CMS.update(fn), []);
  return [state, setKey, update];
};

window.useEditMode = function () {
  const [editing, setEditing] = useState(!!window.__EXEC_EDIT_MODE);
  useEffect(() => {
    document.body.classList.toggle('edit-mode', editing);
    window.__EXEC_EDIT_MODE = editing;
  }, [editing]);
  return [editing, setEditing];
};

// ============ INLINE EDITABLE TEXT ============
// Live contentEditable. Renders read-only when `editing` is false.
// Saves on blur. Render the current value as children of the contentEditable
// element so initial paint is correct. We then *avoid* re-rendering on every
// keystroke by remembering the last value we committed: if the DOM already
// matches the value prop, we don't touch it. This keeps the caret stable
// while the user types but still picks up external updates (resets etc).
window.EditableText = React.memo(function EditableText({
  value, onChange, editing, as = 'span', placeholder = '…',
  multiline = false, className = '', style = {}, maxLength,
}) {
  const ref = useRef(null);
  const Tag = as;

  // After mount / value change, only set DOM text if it differs from prop.
  // This catches "reset" and "edit elsewhere" updates while leaving caret
  // alone during normal typing.
  useEffect(() => {
    if (!ref.current) return;
    const next = value == null ? '' : String(value);
    if (ref.current.innerText !== next && document.activeElement !== ref.current) {
      ref.current.innerText = next;
    }
  });

  if (!editing) {
    return <Tag className={className} style={style}>{value || placeholder}</Tag>;
  }

  const commit = () => {
    let next = ref.current.innerText || '';
    if (maxLength && next.length > maxLength) next = next.slice(0, maxLength);
    if (next !== value) onChange(next);
  };

  const onKey = (e) => {
    if (!multiline && e.key === 'Enter') { e.preventDefault(); ref.current.blur(); }
    if (e.key === 'Escape') { ref.current.blur(); }
  };

  return (
    <Tag
      ref={ref}
      className={`editable ${className}`}
      style={style}
      contentEditable
      suppressContentEditableWarning
      onBlur={commit}
      onKeyDown={onKey}
      onClick={(e) => e.stopPropagation()}
      data-placeholder={placeholder}
    >
      {value}
    </Tag>
  );
}, (prev, next) => {
  // Re-render when editing flips or value changes (the useEffect above
  // decides whether to actually touch the DOM).
  return prev.value === next.value && prev.editing === next.editing && prev.placeholder === next.placeholder;
});

// ============ EDITABLE LINK (label + url) ============
window.EditableUrl = function EditableUrl({
  label, url, onChange, editing, className = '',
}) {
  const [open, setOpen] = useState(false);
  const [draftLabel, setDraftLabel] = useState(label);
  const [draftUrl, setDraftUrl] = useState(url);
  useEffect(() => { setDraftLabel(label); setDraftUrl(url); }, [label, url, open]);

  if (!editing) {
    return <a href={url || '#'} className={className}>{label}</a>;
  }
  const save = () => {
    onChange({ label: draftLabel, url: draftUrl });
    setOpen(false);
  };
  return (
    <>
      <button
        type="button"
        className={`editable-link ${className}`}
        onClick={() => setOpen(true)}
        title={`Edit · ${url}`}
      >
        <span>{label}</span>
        <svg viewBox="0 0 24 24" width="10" height="10" fill="none" stroke="currentColor" strokeWidth="1.8"><path d="M14 4l6 6-9 9H5v-6l9-9Z"/></svg>
      </button>
      {open && (
        <div className="adm-pop-scrim" onClick={() => setOpen(false)}>
          <div className="adm-pop" onClick={(e) => e.stopPropagation()}>
            <div className="adm-pop-h">EDIT LINK</div>
            <label className="adm-pop-f">
              <span>LABEL</span>
              <input value={draftLabel} onChange={(e) => setDraftLabel(e.target.value)} autoFocus/>
            </label>
            <label className="adm-pop-f">
              <span>URL</span>
              <input value={draftUrl} onChange={(e) => setDraftUrl(e.target.value)} placeholder="https://…"/>
            </label>
            <div className="adm-pop-acts">
              <button type="button" className="btn ghost" onClick={() => setOpen(false)}>CANCEL</button>
              <button type="button" className="btn primary" onClick={save}>SAVE</button>
            </div>
          </div>
        </div>
      )}
    </>
  );
};

// ============ ADD BUTTON / ADD TILE ============
window.AdminAddButton = function AdminAddButton({ onClick, label = 'ADD', className = '', style = {} }) {
  return (
    <button type="button" className={`adm-add ${className}`} style={style} onClick={onClick}>
      <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="2"><path d="M12 5v14M5 12h14"/></svg>
      <span>{label}</span>
    </button>
  );
};

// ============ ITEM CONTROLS (delete, up/down) ============
window.AdminItemControls = function AdminItemControls({ onDelete, onUp, onDown, className = '' }) {
  return (
    <div className={`adm-ctl ${className}`} onClick={(e) => e.stopPropagation()}>
      {onUp   && <button type="button" className="adm-ctl-b" onClick={onUp}    title="Move up">↑</button>}
      {onDown && <button type="button" className="adm-ctl-b" onClick={onDown}  title="Move down">↓</button>}
      {onDelete && (
        <button type="button" className="adm-ctl-b danger" onClick={onDelete} title="Delete">
          <svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" strokeWidth="1.8"><path d="M6 6l12 12M18 6 6 18"/></svg>
        </button>
      )}
    </div>
  );
};

// ============ ADMIN BAR (floating, top) ============
window.AdminBar = function AdminBar({ editing, setEditing, extraActions }) {
  const isAdmin = window.CMS.isAdmin();
  if (!isAdmin) return null;
  const logout = () => {
    if (!confirm('Sign out of admin and exit edit mode?')) return;
    window.CMS.logout();
    setEditing(false);
    window.location.reload();
  };
  const reset = () => {
    if (!confirm('Reset ALL content to defaults? This cannot be undone.')) return;
    window.CMS.reset();
  };
  return (
    <div className="adm-bar">
      <div className="adm-bar-l">
        <span className="dot pulse"></span>
        <span className="adm-bar-tag">ADMIN //</span>
        <span className="adm-bar-state">{editing ? 'EDITING' : 'PREVIEW'}</span>
      </div>
      <div className="adm-bar-r">
        {extraActions}
        <button type="button" className="adm-bar-btn" onClick={() => setEditing(!editing)}>
          {editing ? 'EXIT EDIT' : 'EDIT PAGE'}
        </button>
        <button type="button" className="adm-bar-btn" onClick={reset} title="Reset all edits">RESET</button>
        <button type="button" className="adm-bar-btn danger" onClick={logout}>LOGOUT</button>
      </div>
    </div>
  );
};

// ============ STATUS PICKER (small popover for edit-status) ============
window.StatusPicker = function StatusPicker({ value, onChange, options = ['online','offline','updating'] }) {
  const [open, setOpen] = useState(false);
  return (
    <div className="adm-statpick" onClick={(e) => e.stopPropagation()}>
      <button
        type="button"
        className={`adm-statpick-cur ${value}`}
        onClick={() => setOpen((o) => !o)}
        title="Click to change status"
      >
        <span className="dot"></span>
        <span>{value.toUpperCase()}</span>
        <span className="adm-statpick-chev">▾</span>
      </button>
      {open && (
        <div className="adm-statpick-menu">
          {options.map((opt) => (
            <button
              key={opt}
              type="button"
              className={`adm-statpick-opt ${opt} ${opt === value ? 'active' : ''}`}
              onClick={() => { onChange(opt); setOpen(false); }}
            >
              <span className="dot"></span>
              <span>{opt.toUpperCase()}</span>
            </button>
          ))}
        </div>
      )}
    </div>
  );
};
