import React, { useEffect, useCallback, useRef } from 'react';
import { useEditor } from '@craftjs/core';
import { useSitesmithModal } from '../../state/SitesmithContext';
import { buildSitesmithTarget } from '../../utils/sitesmith-target';
import { regenerateTreeIds } from '../../utils/craft-tree';
import { getClipboardTree, setClipboardTree } from '../../hooks/clipboard';
import { useNodeActions } from '../../hooks/useNodeActions';

interface ContextMenuProps {
  visible: boolean;
  x: number;
  y: number;
  nodeId: string | null;
  onClose: () => void;
}

interface MenuItem {
  label: string;
  /** Font Awesome icon suffix (e.g. 'magic' for fa-magic), rendered before the label. */
  icon?: string;
  shortcut?: string;
  action: () => void;
  danger?: boolean;
  disabled?: boolean;
  dividerAfter?: boolean;
}

export const ContextMenu: React.FC<ContextMenuProps> = ({
  visible,
  x,
  y,
  nodeId,
  onClose,
}) => {
  const { actions, query } = useEditor();
  const { open: openSitesmith } = useSitesmithModal();
  const menuRef = useRef<HTMLDivElement>(null);

  // Close on click outside
  useEffect(() => {
    if (!visible) return;
    const handleClick = (e: MouseEvent) => {
      if (menuRef.current && !menuRef.current.contains(e.target as Node)) {
        onClose();
      }
    };
    const handleEsc = (e: KeyboardEvent) => {
      if (e.key === 'Escape') onClose();
    };
    document.addEventListener('mousedown', handleClick);
    document.addEventListener('keydown', handleEsc);
    return () => {
      document.removeEventListener('mousedown', handleClick);
      document.removeEventListener('keydown', handleEsc);
    };
  }, [visible, onClose]);

  const getParentId = useCallback((): string | null => {
    if (!nodeId) return null;
    try {
      const node = query.node(nodeId).get();
      return node?.data?.parent || null;
    } catch {
      return null;
    }
  }, [nodeId, query]);

  // Shared move/duplicate/delete/select-parent logic (item 1, Phase B) --
  // extracted into `useNodeActions` so the mobile selection toolbar drives
  // the exact same behavior. Wrapped here purely to also `onClose()` the
  // menu after each action, same as before the extraction.
  const nodeActions = useNodeActions(nodeId);

  const duplicate = useCallback(() => {
    nodeActions.duplicate();
    onClose();
  }, [nodeActions, onClose]);

  const copyNode = useCallback(() => {
    if (!nodeId || nodeId === 'ROOT') return;
    try {
      // Store a detached subtree snapshot, not just the id -- an id-based
      // clipboard can't survive a page switch (the copied id no longer
      // exists in `query` once the canvas is re-deserialized to a different
      // page's Craft.js state). See clipboard.ts.
      setClipboardTree(query.node(nodeId).toNodeTree());
    } catch (e) {
      console.error('Copy failed:', e);
    }
    onClose();
  }, [nodeId, query, onClose]);

  const pasteNode = useCallback(() => {
    const clip = getClipboardTree();
    if (!clip) {
      onClose();
      return;
    }
    try {
      // Paste as a SIBLING of the right-clicked node (immediately after it,
      // matching duplicate()'s UX), not as its child -- using the clicked
      // node itself as the parent throws when it's a leaf. Falls back to
      // appending into ROOT when nothing valid was right-clicked. This works
      // regardless of which page is on the canvas -- the clipboard tree is a
      // detached snapshot, not a reference to a node that may not exist here.
      let targetParent = 'ROOT';
      let insertIndex: number | undefined;
      if (nodeId && nodeId !== 'ROOT') {
        const clickedNode = query.node(nodeId).get();
        const parentId: string | null | undefined = clickedNode?.data?.parent;
        if (parentId) {
          targetParent = parentId;
          try {
            const siblings: string[] = query.node(parentId).get()?.data?.nodes || [];
            const idx = siblings.indexOf(nodeId);
            if (idx !== -1) insertIndex = idx + 1;
          } catch {
            // Leave insertIndex undefined -- addNodeTree appends when omitted.
          }
        }
      }

      const tree = regenerateTreeIds(clip);
      if (insertIndex !== undefined) {
        actions.addNodeTree(tree, targetParent, insertIndex);
      } else {
        actions.addNodeTree(tree, targetParent);
      }
      actions.selectNode(tree.rootNodeId);
    } catch (e) {
      console.error('Paste failed:', e);
    }
    onClose();
  }, [nodeId, actions, query, onClose]);

  const moveUp = useCallback(() => {
    nodeActions.moveUp();
    onClose();
  }, [nodeActions, onClose]);

  const moveDown = useCallback(() => {
    nodeActions.moveDown();
    onClose();
  }, [nodeActions, onClose]);

  const selectParent = useCallback(() => {
    nodeActions.selectParent();
    onClose();
  }, [nodeActions, onClose]);

  const askSitesmith = useCallback(() => {
    if (!nodeId || nodeId === 'ROOT') return;
    try {
      const target = buildSitesmithTarget(query, nodeId);
      if (target) openSitesmith(target);
    } catch (e) {
      console.error('Ask Sitesmith failed:', e);
    }
    onClose();
  }, [nodeId, query, openSitesmith, onClose]);

  const deleteNode = useCallback(() => {
    nodeActions.deleteNode();
    onClose();
  }, [nodeActions, onClose]);

  if (!visible) return null;

  const isRoot = nodeId === 'ROOT' || !nodeId;

  const items: MenuItem[] = [
    {
      label: 'Ask Sitesmith',
      icon: 'magic',
      action: askSitesmith,
      disabled: isRoot,
      dividerAfter: true,
    },
    {
      label: 'Duplicate',
      icon: 'clone',
      shortcut: 'Ctrl+D',
      action: duplicate,
      disabled: isRoot,
    },
    {
      label: 'Copy',
      icon: 'files-o',
      shortcut: 'Ctrl+C',
      action: copyNode,
      disabled: isRoot,
    },
    {
      label: 'Paste',
      icon: 'clipboard',
      shortcut: 'Ctrl+V',
      action: pasteNode,
      disabled: !getClipboardTree(),
      dividerAfter: true,
    },
    {
      label: 'Move Up',
      icon: 'arrow-up',
      action: moveUp,
      disabled: isRoot,
    },
    {
      label: 'Move Down',
      icon: 'arrow-down',
      action: moveDown,
      disabled: isRoot,
    },
    {
      label: 'Select Parent',
      icon: 'level-up',
      action: selectParent,
      // Not just `isRoot`: the real dead-end is when nodeId's PARENT is
      // ROOT (selecting a top-level section -> Select Parent would only
      // select the page-wide, un-editable ROOT -- no outline, no toolbar).
      // `canSelectParent` (useNodeActions) already encodes that and matches
      // the mobile selection toolbar's identical guard.
      disabled: !nodeActions.canSelectParent,
      dividerAfter: true,
    },
    {
      label: 'Delete',
      icon: 'trash',
      shortcut: 'Del',
      action: deleteNode,
      danger: true,
      disabled: isRoot,
    },
  ];

  // Adjust position to stay within viewport
  const adjustedX = Math.min(x, window.innerWidth - 200);
  const adjustedY = Math.min(y, window.innerHeight - items.length * 34 - 10);

  return (
    <div
      ref={menuRef}
      style={{
        position: 'fixed',
        top: adjustedY,
        left: adjustedX,
        zIndex: 10000,
        minWidth: 180,
        background: 'var(--color-bg-elevated)',
        border: '1px solid var(--color-border)',
        borderRadius: 'var(--radius-md)',
        boxShadow: '0 8px 24px rgba(0,0,0,0.5)',
        padding: '4px 0',
        overflow: 'hidden',
      }}
    >
      {items.map((item, i) => (
        <React.Fragment key={item.label}>
          <button
            onClick={item.disabled ? undefined : item.action}
            disabled={item.disabled}
            style={{
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'space-between',
              width: '100%',
              padding: '7px 12px',
              fontSize: 12,
              color: item.disabled
                ? 'var(--color-text-dim)'
                : item.danger
                  ? 'var(--color-danger)'
                  : 'var(--color-text)',
              background: 'transparent',
              border: 'none',
              cursor: item.disabled ? 'default' : 'pointer',
              textAlign: 'left',
              transition: 'background var(--transition-fast)',
            }}
            onMouseEnter={(e) => {
              if (!item.disabled) {
                (e.target as HTMLElement).style.background = 'var(--color-bg-hover)';
              }
            }}
            onMouseLeave={(e) => {
              (e.target as HTMLElement).style.background = 'transparent';
            }}
          >
            <span>
              {item.icon && <i className={`fa fa-${item.icon}`} style={{ marginRight: 6, width: 12 }} />}
              {item.label}
            </span>
            {item.shortcut && (
              <span
                style={{
                  fontSize: 10,
                  color: 'var(--color-text-dim)',
                  marginLeft: 16,
                }}
              >
                {item.shortcut}
              </span>
            )}
          </button>
          {item.dividerAfter && (
            <div
              style={{
                height: 1,
                background: 'var(--color-border)',
                margin: '4px 0',
              }}
            />
          )}
        </React.Fragment>
      ))}
    </div>
  );
};
