import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import CustomNode from '../CustomNode';
import { Position } from 'reactflow';

// Mock reactflow Handle component
jest.mock('reactflow', () => ({
  Handle: ({ type, position, id }: any) => (
    <div data-testid={`handle-${type}-${id}`} data-position={position}>
      Handle
    </div>
  ),
  Position: {
    Top: 'top',
    Bottom: 'bottom',
    Left: 'left',
    Right: 'right',
  },
}));

describe('CustomNode', () => {
  const defaultNodeData = {
    label: 'Test Node',
    plugin: 'test_plugin',
    locked: false,
    configured: false,
    annotation: '',
    isAnnotationVisible: false,
    isLocked: false,
    onDelete: jest.fn(),
    onToggleAnnotation: jest.fn(),
  };

  const defaultProps = {
    id: 'node1',
    type: 'element',
    data: defaultNodeData,
    selected: false,
    xPos: 0,
    yPos: 0,
    dragging: false,
    isConnectable: true,
    zIndex: 0,
    positionAbsoluteX: 0,
    positionAbsoluteY: 0,
    sourcePosition: Position.Bottom,
    targetPosition: Position.Top,
  };

  beforeEach(() => {
    jest.clearAllMocks();
  });

  describe('rendering', () => {
    it('should render node container', () => {
      render(<CustomNode {...defaultProps} />);
      expect(document.querySelector('.custom-node')).toBeInTheDocument();
    });

    it('should render action-node class', () => {
      render(<CustomNode {...defaultProps} />);
      expect(document.querySelector('.action-node')).toBeInTheDocument();
    });

    it('should render node label', () => {
      render(<CustomNode {...defaultProps} />);
      expect(screen.getByText('Test Node')).toBeInTheDocument();
    });

    it('should render plugin name', () => {
      render(<CustomNode {...defaultProps} />);
      expect(screen.getByText('test_plugin')).toBeInTheDocument();
    });

    it('should render node type indicator', () => {
      render(<CustomNode {...defaultProps} />);
      expect(screen.getByText('Element')).toBeInTheDocument();
    });

    it('should render input handle', () => {
      render(<CustomNode {...defaultProps} />);
      expect(screen.getByTestId('handle-target-input')).toBeInTheDocument();
    });

    it('should render output handle', () => {
      render(<CustomNode {...defaultProps} />);
      expect(screen.getByTestId('handle-source-output')).toBeInTheDocument();
    });
  });

  describe('selected state', () => {
    it('should add selected class when selected and not locked', () => {
      render(<CustomNode {...defaultProps} selected={true} />);
      expect(document.querySelector('.custom-node.selected')).toBeInTheDocument();
    });

    it('should not add selected class when selected but locked', () => {
      const data = { ...defaultNodeData, locked: true };
      render(<CustomNode {...defaultProps} data={data} selected={true} />);
      expect(document.querySelector('.custom-node.selected')).not.toBeInTheDocument();
    });
  });

  describe('locked state', () => {
    it('should add node-locked class when locked', () => {
      const data = { ...defaultNodeData, locked: true };
      render(<CustomNode {...defaultProps} data={data} />);
      expect(document.querySelector('.node-locked')).toBeInTheDocument();
    });

    it('should render lock icon when locked', () => {
      const data = { ...defaultNodeData, locked: true };
      render(<CustomNode {...defaultProps} data={data} />);
      expect(document.querySelector('.lock-icon')).toBeInTheDocument();
    });

    it('should not render lock icon when not locked', () => {
      render(<CustomNode {...defaultProps} />);
      expect(document.querySelector('.lock-icon')).not.toBeInTheDocument();
    });
  });

  describe('configured state', () => {
    it('should render configured icon when configured', () => {
      const data = { ...defaultNodeData, configured: true };
      render(<CustomNode {...defaultProps} data={data} />);
      expect(document.querySelector('.configured-icon')).toBeInTheDocument();
    });

    it('should not render configured icon when not configured', () => {
      render(<CustomNode {...defaultProps} />);
      expect(document.querySelector('.configured-icon')).not.toBeInTheDocument();
    });
  });

  describe('annotation', () => {
    it('should add annotation class when has annotation', () => {
      const data = { ...defaultNodeData, annotation: 'Test annotation' };
      render(<CustomNode {...defaultProps} data={data} />);
      expect(document.querySelector('.node-has-annotation')).toBeInTheDocument();
    });

    it('should render annotation icon when has annotation', () => {
      const data = { ...defaultNodeData, annotation: 'Test annotation' };
      render(<CustomNode {...defaultProps} data={data} />);
      expect(document.querySelector('.annotation-icon')).toBeInTheDocument();
    });

    it('should add active class to annotation icon when visible', () => {
      const data = { ...defaultNodeData, annotation: 'Test', isAnnotationVisible: true };
      render(<CustomNode {...defaultProps} data={data} />);
      expect(document.querySelector('.annotation-icon.active')).toBeInTheDocument();
    });

    it('should call onToggleAnnotation when annotation icon clicked', () => {
      const onToggleAnnotation = jest.fn();
      const data = { ...defaultNodeData, annotation: 'Test', onToggleAnnotation };
      render(<CustomNode {...defaultProps} data={data} />);

      fireEvent.click(document.querySelector('.annotation-icon')!);

      expect(onToggleAnnotation).toHaveBeenCalled();
    });

    it('should stop propagation when annotation icon clicked', () => {
      const onToggleAnnotation = jest.fn();
      const data = { ...defaultNodeData, annotation: 'Test', onToggleAnnotation };
      render(<CustomNode {...defaultProps} data={data} />);

      fireEvent.click(document.querySelector('.annotation-icon')!);

      // stopPropagation should have been called
      expect(onToggleAnnotation).toHaveBeenCalled();
    });
  });

  describe('delete button', () => {
    it('should render delete button when not locked', () => {
      render(<CustomNode {...defaultProps} />);
      expect(document.querySelector('.node-delete-btn')).toBeInTheDocument();
    });

    it('should not render delete button when locked', () => {
      const data = { ...defaultNodeData, locked: true };
      render(<CustomNode {...defaultProps} data={data} />);
      expect(document.querySelector('.node-delete-btn')).not.toBeInTheDocument();
    });

    it('should not render delete button when isLocked is true', () => {
      const data = { ...defaultNodeData, isLocked: true };
      render(<CustomNode {...defaultProps} data={data} />);
      expect(document.querySelector('.node-delete-btn')).not.toBeInTheDocument();
    });

    it('should call onDelete when delete button clicked', () => {
      const onDelete = jest.fn();
      const data = { ...defaultNodeData, onDelete };
      render(<CustomNode {...defaultProps} data={data} />);

      fireEvent.click(document.querySelector('.node-delete-btn')!);

      expect(onDelete).toHaveBeenCalled();
    });

    it('should stop propagation when delete button clicked', () => {
      const onDelete = jest.fn();
      const data = { ...defaultNodeData, onDelete };
      render(<CustomNode {...defaultProps} data={data} />);

      fireEvent.click(document.querySelector('.node-delete-btn')!);

      expect(onDelete).toHaveBeenCalled();
    });
  });

  describe('without plugin', () => {
    it('should render without plugin text when not provided', () => {
      const data = { ...defaultNodeData, plugin: undefined };
      render(<CustomNode {...defaultProps} data={data} />);
      expect(screen.queryByText('test_plugin')).not.toBeInTheDocument();
    });
  });

  describe('displayName', () => {
    it('should have correct displayName', () => {
      expect(CustomNode.displayName).toBe('CustomNode');
    });
  });
});
