import { useEffect } from 'react';
import { useEditor } from '@craftjs/core';
import { findDeletableTarget } from '../utils/craft-helpers';
import { regenerateTreeIds } from '../utils/craft-tree';
import { getClipboardTree, setClipboardTree } from './clipboard';

function isInputFocused(): boolean {
  const el = document.activeElement;
  if (!el) return false;
  const tag = el.tagName.toLowerCase();
  if (tag === 'input' || tag === 'textarea' || tag === 'select') return true;
  if ((el as HTMLElement).isContentEditable) return true;
  return false;
}

export function useKeyboardShortcuts() {
  const { actions, query } = useEditor((state) => {
    const selectedIds = state.events.selected;
    const selectedId = selectedIds ? Array.from(selectedIds)[0] : null;
    return { selectedId };
  });

  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      // Skip when typing in inputs
      if (isInputFocused()) return;

      const ctrl = e.ctrlKey || e.metaKey;

      // Ctrl+Z: Undo
      if (ctrl && !e.shiftKey && e.key === 'z') {
        e.preventDefault();
        try {
          actions.history.undo();
        } catch (err) {
          // No more undo steps
        }
        return;
      }

      // Ctrl+Y or Ctrl+Shift+Z: Redo
      if ((ctrl && e.key === 'y') || (ctrl && e.shiftKey && e.key === 'z') || (ctrl && e.shiftKey && e.key === 'Z')) {
        e.preventDefault();
        try {
          actions.history.redo();
        } catch (err) {
          // No more redo steps
        }
        return;
      }

      // Delete/Backspace: delete selected node
      if (e.key === 'Delete' || e.key === 'Backspace') {
        e.preventDefault();
        try {
          const selected = query.getEvent('selected').all();
          if (selected.length > 0) {
            const target = findDeletableTarget(query, selected[0]);
            if (target) actions.delete(target);
          }
        } catch (err) {
          console.error('Delete failed:', err);
        }
        return;
      }

      // Ctrl+D: duplicate selected
      if (ctrl && (e.key === 'd' || e.key === 'D')) {
        e.preventDefault();
        try {
          const selected = query.getEvent('selected').all();
          if (selected.length > 0) {
            const nodeId = selected[0];
            if (nodeId !== 'ROOT') {
              const node = query.node(nodeId).get();
              const parentId = node?.data?.parent;
              if (parentId) {
                const tree = regenerateTreeIds(query.node(nodeId).toNodeTree());
                actions.addNodeTree(tree, parentId);
              }
            }
          }
        } catch (err) {
          console.error('Duplicate failed:', err);
        }
        return;
      }

      // Ctrl+C: copy the selected node's subtree (a detached snapshot, not
      // just its id -- see clipboard.ts for why: an id-based clipboard can't
      // survive a page switch, since the copied id no longer exists in
      // `query` once the canvas is re-deserialized to a different page).
      if (ctrl && (e.key === 'c' || e.key === 'C')) {
        e.preventDefault();
        try {
          const selected = query.getEvent('selected').all();
          if (selected.length > 0 && selected[0] !== 'ROOT') {
            setClipboardTree(query.node(selected[0]).toNodeTree());
          }
        } catch (err) {
          console.error('Copy failed:', err);
        }
        return;
      }

      // Ctrl+V: paste the clipboard tree as a sibling of the current
      // selection (immediately after it, matching duplicate()'s UX), or
      // append to ROOT when nothing is selected. Works regardless of which
      // page is currently on the canvas -- the clipboard tree is a detached
      // snapshot, not a reference to a node that may no longer exist here.
      if (ctrl && (e.key === 'v' || e.key === 'V')) {
        e.preventDefault();
        try {
          const clip = getClipboardTree();
          if (!clip) return;

          const selected = query.getEvent('selected').all();
          const selectedId = selected.length > 0 ? selected[0] : null;

          let targetParentId = 'ROOT';
          let insertIndex: number | undefined;
          if (selectedId && selectedId !== 'ROOT') {
            const node = query.node(selectedId).get();
            const parentId: string | null | undefined = node?.data?.parent;
            if (parentId) {
              targetParentId = parentId;
              try {
                const siblings: string[] = query.node(parentId).get()?.data?.nodes || [];
                const idx = siblings.indexOf(selectedId);
                if (idx !== -1) insertIndex = idx + 1;
              } catch {
                // Leave insertIndex undefined -- addNodeTree appends when omitted.
              }
            }
          }

          const tree = regenerateTreeIds(clip);
          if (insertIndex !== undefined) {
            actions.addNodeTree(tree, targetParentId, insertIndex);
          } else {
            actions.addNodeTree(tree, targetParentId);
          }
          actions.selectNode(tree.rootNodeId);
        } catch (err) {
          console.error('Paste failed:', err);
        }
        return;
      }

      // Escape: deselect all
      if (e.key === 'Escape') {
        e.preventDefault();
        try {
          actions.clearEvents();
        } catch (err) {
          // Ignore
        }
        return;
      }
    };

    document.addEventListener('keydown', handleKeyDown);
    return () => document.removeEventListener('keydown', handleKeyDown);
  }, [actions, query]);
}
