import React, { useCallback, useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import type { EditorStore } from '../../store/editorStore';
import type { CBNode } from '../../types';
import { SHORTCUT_LABELS } from '../../hooks/useShortcuts';

export interface ContextMenuState {
  x: number;
  y: number;
  nodeId: string;
}

interface Props {
  menu: ContextMenuState;
  store: EditorStore;
  onClose: () => void;
}

// ── SVG Icon set ──────────────────────────────────────────────────────────────

const IcCopy = () => (
  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
  </svg>
);
const IcPaste = () => (
  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/>
    <rect x="8" y="2" width="8" height="4" rx="1"/>
  </svg>
);
const IcDuplicate = () => (
  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <rect x="3" y="3" width="13" height="13" rx="2"/><path d="M21 11V21H11"/>
  </svg>
);
const IcStyle = () => (
  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <circle cx="13.5" cy="6.5" r=".5" fill="currentColor" stroke="none"/>
    <circle cx="17.5" cy="10.5" r=".5" fill="currentColor" stroke="none"/>
    <circle cx="8.5" cy="7.5" r=".5" fill="currentColor" stroke="none"/>
    <circle cx="6.5" cy="12.5" r=".5" fill="currentColor" stroke="none"/>
    <path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z"/>
  </svg>
);
const IcTemplate = () => (
  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"/>
    <polyline points="14 2 14 8 20 8"/>
    <line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/>
  </svg>
);
const IcTimeline = () => (
  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <circle cx="6" cy="6" r="2.5"/><circle cx="13" cy="12" r="2.5"/><circle cx="19" cy="18" r="2.5"/>
    <path d="M2 6h1.5M8.5 6H21M2 12h8.5M15.5 12H21M2 18h14.5M21.5 18H21"/>
  </svg>
);
const IcHide = () => (
  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/>
    <line x1="1" y1="1" x2="23" y2="23"/>
  </svg>
);
const IcShow = () => (
  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>
  </svg>
);
const IcLock = () => (
  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>
  </svg>
);
const IcUnlock = () => (
  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 9.9-1"/>
  </svg>
);
const IcDelete = () => (
  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <polyline points="3 6 5 6 21 6"/>
    <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/>
  </svg>
);

// ── Helpers ───────────────────────────────────────────────────────────────────

function findNodeDeep(sections: CBNode[], id: string): CBNode | null {
  for (const s of sections) {
    if (s.id === id) return s;
    if (s.children) {
      const found = findNodeDeep(s.children, id);
      if (found) return found;
    }
  }
  return null;
}

type ItemDef = {
  label: string;
  icon: React.ReactElement;
  action: () => void;
  shortcut?: string;
  disabled?: boolean;
  danger?: boolean;
};
type MenuItem = ItemDef | null; // null = separator

// ── Component ─────────────────────────────────────────────────────────────────

export function ContextMenu({ menu, store, onClose }: Props) {
  const ref = useRef<HTMLDivElement>(null);
  const { state } = store;

  const node = findNodeDeep(state.pageData.sections, menu.nodeId);
  const hasClipboard      = !!state.clipboard;
  const hasStyleClipboard = !!(state as any).styleClipboard;
  const isHiddenAll       = !!(node?.hideOn?.desktop && node?.hideOn?.tablet && node?.hideOn?.mobile);
  const isLocked          = !!node?.locked;

  // Keyboard focus tracking (index into clickableItems)
  const [focusIdx, setFocusIdx] = useState(0);

  // ── Actions ────────────────────────────────────────────────────────────────

  const toggleHide = useCallback(() => {
    const next = !isHiddenAll;
    store.updateNodeHideOn(menu.nodeId, 'desktop', next);
    store.updateNodeHideOn(menu.nodeId, 'tablet',  next);
    store.updateNodeHideOn(menu.nodeId, 'mobile',  next);
    onClose();
  }, [menu.nodeId, isHiddenAll, store, onClose]);

  const toggleLock = useCallback(() => {
    store.lockNode(menu.nodeId, !isLocked);
    onClose();
  }, [menu.nodeId, isLocked, store, onClose]);

  const openSaveTemplate = useCallback(() => {
    window.dispatchEvent(new CustomEvent('cb:openSaveTemplate', { detail: { nodeId: menu.nodeId } }));
    onClose();
  }, [menu.nodeId, onClose]);

  const openTimeline = useCallback(() => {
    window.dispatchEvent(new CustomEvent('cb:openTimeline', { detail: { nodeId: menu.nodeId } }));
    onClose();
  }, [menu.nodeId, onClose]);
  const hasTimelineChildren = (node?.children?.length ?? 0) >= 2;

  // ── Item definitions ───────────────────────────────────────────────────────

  const items: MenuItem[] = [
    { label: 'Copy',      shortcut: SHORTCUT_LABELS.copy,      icon: <IcCopy />,      action: () => { store.copyNode(menu.nodeId); onClose(); } },
    { label: 'Paste',     shortcut: SHORTCUT_LABELS.paste,     icon: <IcPaste />,     action: () => { store.pasteNode(menu.nodeId); onClose(); }, disabled: !hasClipboard },
    { label: 'Duplicate', shortcut: SHORTCUT_LABELS.duplicate, icon: <IcDuplicate />, action: () => { store.duplicateNode(menu.nodeId); onClose(); } },
    null,
    { label: 'Copy Style',  shortcut: SHORTCUT_LABELS.copyStyle,  icon: <IcStyle />, action: () => { (store as any).copyNodeStyle(menu.nodeId); onClose(); } },
    { label: 'Paste Style', shortcut: SHORTCUT_LABELS.pasteStyle, icon: <IcStyle />, action: () => { (store as any).pasteNodeStyle(menu.nodeId); onClose(); }, disabled: !hasStyleClipboard },
    null,
    { label: 'Save as Template', icon: <IcTemplate />, action: openSaveTemplate },
    { label: 'Edit Timeline', icon: <IcTimeline />, action: openTimeline, disabled: !hasTimelineChildren },
    null,
    { label: isHiddenAll ? 'Show Element' : 'Hide Element', icon: isHiddenAll ? <IcShow /> : <IcHide />, action: toggleHide },
    { label: isLocked    ? 'Unlock Element' : 'Lock Element', icon: isLocked ? <IcUnlock /> : <IcLock />, action: toggleLock },
    null,
    { label: 'Delete', shortcut: SHORTCUT_LABELS.delete, icon: <IcDelete />, action: () => { store.deleteNode(menu.nodeId); onClose(); }, danger: true },
  ];

  const clickable = items.filter((i): i is ItemDef => i !== null);

  // ── Keyboard navigation ────────────────────────────────────────────────────

  useEffect(() => {
    const onKey = (e: KeyboardEvent) => {
      if (e.key === 'Escape') { onClose(); return; }

      if (e.key === 'ArrowDown') {
        e.preventDefault();
        setFocusIdx((prev) => {
          let next = prev + 1;
          while (next < clickable.length && clickable[next].disabled) next++;
          return next < clickable.length ? next : prev;
        });
      } else if (e.key === 'ArrowUp') {
        e.preventDefault();
        setFocusIdx((prev) => {
          let p = prev - 1;
          while (p >= 0 && clickable[p].disabled) p--;
          return p >= 0 ? p : prev;
        });
      } else if (e.key === 'Enter') {
        e.preventDefault();
        const item = clickable[focusIdx];
        if (item && !item.disabled) item.action();
      }
    };
    document.addEventListener('keydown', onKey);
    return () => document.removeEventListener('keydown', onKey);
  }, [focusIdx, clickable, onClose]);

  // ── Close on outside click ─────────────────────────────────────────────────

  useEffect(() => {
    const onDown = (e: MouseEvent) => {
      if (ref.current && !ref.current.contains(e.target as Node)) onClose();
    };
    document.addEventListener('mousedown', onDown);
    return () => document.removeEventListener('mousedown', onDown);
  }, [onClose]);

  // ── Flip position to stay inside viewport ──────────────────────────────────

  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    let x = menu.x, y = menu.y;
    if (x + r.width  > window.innerWidth)  x = window.innerWidth  - r.width  - 8;
    if (y + r.height > window.innerHeight) y = window.innerHeight - r.height - 8;
    if (x < 8) x = 8;
    if (y < 8) y = 8;
    el.style.left = x + 'px';
    el.style.top  = y + 'px';
  }, [menu.x, menu.y]);

  // ── Node type label ────────────────────────────────────────────────────────

  const typeLabel = node ? node.type.charAt(0).toUpperCase() + node.type.slice(1) : 'Element';

  // ── Render ─────────────────────────────────────────────────────────────────

  let ci = 0; // clickable index counter for rendering

  return createPortal(
    <div
      ref={ref}
      className="jalpi-ctx-menu"
      role="menu"
      style={{ left: menu.x, top: menu.y }}
      onClick={(e) => e.stopPropagation()}
      onContextMenu={(e) => e.preventDefault()}
    >
      <div className="jalpi-ctx-menu__header">{typeLabel}</div>

      {items.map((item, i) => {
          if (item === null) return <div key={`sep-${i}`} className="jalpi-ctx-menu__sep" />;
          const myIdx = ci++;
          return (
            <button
              key={item.label}
              role="menuitem"
              className={[
                'jalpi-ctx-menu__item',
                item.danger    ? 'is-danger'   : '',
                item.disabled  ? 'is-disabled' : '',
                focusIdx === myIdx && !item.disabled ? 'is-focused' : '',
              ].filter(Boolean).join(' ')}
              onClick={item.disabled ? undefined : item.action}
              disabled={!!item.disabled}
              onMouseEnter={() => !item.disabled && setFocusIdx(myIdx)}
              tabIndex={-1}
            >
              <span className="jalpi-ctx-menu__icon">{item.icon}</span>
              <span className="jalpi-ctx-menu__label">{item.label}</span>
              {item.shortcut && <kbd className="jalpi-ctx-menu__shortcut">{item.shortcut}</kbd>}
            </button>
          );
        })}
    </div>,
    document.body
  );
}
