import { describe, test, expect, vi, beforeEach } from 'vitest';
import React from 'react';
import { createRoot, Root } from 'react-dom/client';
import { act } from 'react-dom/test-utils';

/* Same DOM-harness pattern as Footer.editguard.test.tsx: mock @craftjs/core
   so RenderNode (the <Editor onRender> override) can be driven without a
   real Editor tree. document.body doubles as the portal target, same as
   the component itself uses. */
let mockNode: {
  id: string;
  selected: boolean;
  hovered: boolean;
  dom: HTMLElement | null;
  displayName: string;
  parent: string | null;
  isCanvas: boolean;
};
const selectNodeSpy = vi.fn();

vi.mock('@craftjs/core', () => ({
  useEditor: () => ({ actions: { selectNode: selectNodeSpy } }),
  useNode: (collect?: (node: any) => any) => {
    const node = {
      events: { selected: mockNode.selected, hovered: mockNode.hovered },
      dom: mockNode.dom,
      data: {
        custom: {},
        displayName: mockNode.displayName,
        parent: mockNode.parent,
        isCanvas: mockNode.isCanvas,
      },
    };
    return { id: mockNode.id, ...(collect ? collect(node) : {}) };
  },
}));

import { RenderNode } from './RenderNode';

let container: HTMLDivElement;
let root: Root;
let nodeDom: HTMLElement;

function render(ui: React.ReactElement) {
  container = document.createElement('div');
  document.body.appendChild(container);
  act(() => {
    root = createRoot(container);
    root.render(ui);
  });
}

beforeEach(() => {
  nodeDom = document.createElement('div');
  document.body.appendChild(nodeDom);
  mockNode = {
    id: 'node-1',
    selected: false,
    hovered: false,
    dom: nodeDom,
    displayName: 'Heading',
    parent: 'ROOT',
    isCanvas: false,
  };
  selectNodeSpy.mockClear();
});

const rendered = <span data-testid="inner">hello</span>;

describe('RenderNode (Editor onRender override)', () => {
  test('passes render through untouched when not selected', () => {
    render(<RenderNode render={rendered} />);
    expect(container.querySelector('[data-testid="inner"]')).not.toBeNull();
    expect(document.querySelector('.component-indicator')).toBeNull();
    container.remove();
    nodeDom.remove();
  });

  test('shows the badge with the displayName when selected', () => {
    mockNode.selected = true;
    render(<RenderNode render={rendered} />);
    const badge = document.querySelector('.component-indicator');
    expect(badge).not.toBeNull();
    expect(badge?.textContent).toContain('Heading');
    container.remove();
    nodeDom.remove();
    document.querySelector('.component-indicator')?.remove();
  });

  test('never shows a badge for ROOT even if "selected"', () => {
    mockNode.selected = true;
    mockNode.id = 'ROOT';
    render(<RenderNode render={rendered} />);
    expect(document.querySelector('.component-indicator')).toBeNull();
    container.remove();
    nodeDom.remove();
  });

  test('chevron click selects the parent node', () => {
    mockNode.selected = true;
    mockNode.parent = 'parent-42';
    render(<RenderNode render={rendered} />);
    const chevron = document.querySelector('.component-indicator-parent-btn') as HTMLElement;
    expect(chevron).not.toBeNull();
    act(() => {
      chevron.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
    });
    expect(selectNodeSpy).toHaveBeenCalledWith('parent-42');
    container.remove();
    nodeDom.remove();
    document.querySelector('.component-indicator')?.remove();
  });

  test('no chevron when there is no parent', () => {
    mockNode.selected = true;
    mockNode.parent = null;
    render(<RenderNode render={rendered} />);
    expect(document.querySelector('.component-indicator-parent-btn')).toBeNull();
    container.remove();
    nodeDom.remove();
    document.querySelector('.component-indicator')?.remove();
  });

  test('tags a droppable (isCanvas) node dom with data-craft-node', () => {
    mockNode.isCanvas = true;
    render(<RenderNode render={rendered} />);
    expect(nodeDom.hasAttribute('data-craft-node')).toBe(true);
    container.remove();
    nodeDom.remove();
  });

  test('does not tag a non-canvas (leaf) node dom with data-craft-node', () => {
    mockNode.isCanvas = false;
    render(<RenderNode render={rendered} />);
    expect(nodeDom.hasAttribute('data-craft-node')).toBe(false);
    container.remove();
    nodeDom.remove();
  });

  test('never tags ROOT with data-craft-node even though ROOT is a canvas', () => {
    mockNode.id = 'ROOT';
    mockNode.isCanvas = true;
    render(<RenderNode render={rendered} />);
    expect(nodeDom.hasAttribute('data-craft-node')).toBe(false);
    container.remove();
    nodeDom.remove();
  });

  test('tags the dom with data-craft-hovered when the Craft hovered event is set (Layers panel hover sync)', () => {
    mockNode.hovered = true;
    render(<RenderNode render={rendered} />);
    expect(nodeDom.hasAttribute('data-craft-hovered')).toBe(true);
    container.remove();
    nodeDom.remove();
  });

  test('removes data-craft-hovered once the hovered event clears', () => {
    mockNode.hovered = true;
    render(<RenderNode render={rendered} />);
    expect(nodeDom.hasAttribute('data-craft-hovered')).toBe(true);
    mockNode.hovered = false;
    act(() => {
      root.render(<RenderNode render={rendered} />);
    });
    expect(nodeDom.hasAttribute('data-craft-hovered')).toBe(false);
    container.remove();
    nodeDom.remove();
  });
});
